From: Sylvestre Ledru Date: Mon, 17 Sep 2018 11:51:03 +0000 (+0100) Subject: Import llvm-toolchain-7_7.orig-libcxxabi.tar.bz2 X-Git-Tag: archive/raspbian/1%7-6+rpi1~69^6 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=d0fc977d62f383796ae32718b84ce6ded1b5c0e4;p=llvm-toolchain-7.git Import llvm-toolchain-7_7.orig-libcxxabi.tar.bz2 [dgit import orig llvm-toolchain-7_7.orig-libcxxabi.tar.bz2] --- d0fc977d62f383796ae32718b84ce6ded1b5c0e4 diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 000000000..08cd16ead --- /dev/null +++ b/.arcconfig @@ -0,0 +1,4 @@ +{ + "repository.callsign" : "CXXA", + "conduit_uri" : "https://reviews.llvm.org/" +} diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..2d1d3bee6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +BasedOnStyle: LLVM + +--- +Language: Cpp + +AlwaysBreakTemplateDeclarations: true +PointerAlignment: Left + +# Disable formatting options which may break tests. +SortIncludes: false +ReflowComments: false +--- diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..39a2e3a07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# vim swap files +.*.sw? +.sw? + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +#lib/ # We actually have things checked in to lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..d6648ede1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,487 @@ +# See www/CMake.html for instructions on how to build libcxxabi with CMake. + +#=============================================================================== +# Setup Project +#=============================================================================== + +cmake_minimum_required(VERSION 3.4.3) + +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) # Set MACOSX_RPATH=YES by default +endif() + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + ${CMAKE_MODULE_PATH} + ) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(libcxxabi CXX C) + + set(PACKAGE_NAME libcxxabi) + set(PACKAGE_VERSION 7.0.0svn) + set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") + set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") + + # Find the LLVM sources and simulate LLVM CMake options. + include(HandleOutOfTreeLLVM) +endif() + +# Require out of source build. +include(MacroEnsureOutOfSourceBuild) +MACRO_ENSURE_OUT_OF_SOURCE_BUILD( + "${PROJECT_NAME} requires an out of source build. Please create a separate + build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there." + ) + +#=============================================================================== +# Setup CMake Options +#=============================================================================== +include(CMakeDependentOption) +include(HandleCompilerRT) + +# Define options. +option(LIBCXXABI_ENABLE_EXCEPTIONS "Use exceptions." ON) +option(LIBCXXABI_ENABLE_ASSERTIONS "Enable assertions independent of build mode." ON) +option(LIBCXXABI_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) +option(LIBCXXABI_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) +option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." OFF) +option(LIBCXXABI_ENABLE_STATIC_UNWINDER "Statically link the LLVM unwinder." OFF) +option(LIBCXXABI_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF) +option(LIBCXXABI_ENABLE_THREADS "Build with threads enabled" ON) +option(LIBCXXABI_HAS_PTHREAD_API "Ignore auto-detection and force use of pthread API" OFF) +option(LIBCXXABI_HAS_EXTERNAL_THREAD_API + "Build libc++abi with an externalized threading API. + This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON." OFF) +option(LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY + "Build libc++abi with an externalized threading library. + This option may only be set to ON when LIBCXXABI_ENABLE_THREADS=ON" OFF) + +# FIXME: This option should default to off. Unfortunatly GCC 4.9 fails to link +# programs to due undefined references to new/delete in libc++abi. Once this +# has been fixed or worked around the default value should be changed. +option(LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS + "Build libc++abi with definitions for operator new/delete. Normally libc++ + provides these definitions" ON) +option(LIBCXXABI_BUILD_32_BITS "Build 32 bit libc++abi." ${LLVM_BUILD_32_BITS}) +option(LIBCXXABI_INCLUDE_TESTS "Generate build targets for the libc++abi unit tests." ${LLVM_INCLUDE_TESTS}) +set(LIBCXXABI_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING + "Define suffix of library directory name (32/64)") +option(LIBCXXABI_INSTALL_LIBRARY "Install the libc++abi library." ON) +set(LIBCXXABI_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.") +set(LIBCXXABI_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.") +set(LIBCXXABI_SYSROOT "" CACHE PATH "Sysroot for cross compiling.") +set(LIBCXXABI_LIBCXX_LIBRARY_PATH "" CACHE PATH "The path to libc++ library.") + +# Default to building a shared library so that the default options still test +# the libc++abi that is being built. There are two problems with testing a +# static libc++abi. In the case of a standalone build, the tests will link the +# system's libc++, which might not have been built against our libc++abi. In the +# case of an in tree build, libc++ will prefer a dynamic libc++abi from the +# system over a static libc++abi from the output directory. +option(LIBCXXABI_ENABLE_SHARED "Build libc++abi as a shared library." ON) +option(LIBCXXABI_ENABLE_STATIC "Build libc++abi as a static library." ON) + +cmake_dependent_option(LIBCXXABI_INSTALL_STATIC_LIBRARY + "Install the static libc++abi library." ON + "LIBCXXABI_ENABLE_STATIC;LIBCXXABI_INSTALL_LIBRARY" OFF) +cmake_dependent_option(LIBCXXABI_INSTALL_SHARED_LIBRARY + "Install the shared libc++abi library." ON + "LIBCXXABI_ENABLE_SHARED;LIBCXXABI_INSTALL_LIBRARY" OFF) + +cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY + "Statically link the LLVM unwinder to static library" ON + "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_STATIC" OFF) +cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY + "Statically link the LLVM unwinder to shared library" ON + "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_SHARED" OFF) + +option(LIBCXXABI_BAREMETAL "Build libc++abi for baremetal targets." OFF) +# The default terminate handler attempts to demangle uncaught exceptions, which +# causes extra I/O and demangling code to be pulled in. +option(LIBCXXABI_SILENT_TERMINATE "Set this to make the terminate handler default to a silent alternative" OFF) + +if (NOT LIBCXXABI_ENABLE_SHARED AND NOT LIBCXXABI_ENABLE_STATIC) + message(FATAL_ERROR "libc++abi must be built as either a shared or static library.") +endif() + +if (LLVM_EXTERNAL_LIBCXX_SOURCE_DIR) + set(LIBCXXABI_LIBCXX_SRC_DIRS ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR}) +else() + set(LIBCXXABI_LIBCXX_SRC_DIRS + "${LLVM_MAIN_SRC_DIR}/projects/libcxx" + "${LLVM_MAIN_SRC_DIR}/runtimes/libcxx" + "${LLVM_MAIN_SRC_DIR}/../libcxx" + ) +endif() + +set(LIBCXXABI_LIBCXX_INCLUDE_DIRS "") +foreach(dir ${LIBCXXABI_LIBCXX_SRC_DIRS}) + list(APPEND LIBCXXABI_LIBCXX_INCLUDE_DIRS "${dir}/include") +endforeach() + +find_path( + LIBCXXABI_LIBCXX_INCLUDES + __config + PATHS ${LIBCXXABI_LIBCXX_INCLUDES} + ${LIBCXXABI_LIBCXX_PATH}/include + ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBCXX_INCLUDES} + ${LIBCXXABI_LIBCXX_INCLUDE_DIRS} + ${LLVM_INCLUDE_DIR}/c++/v1 + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + +set(LIBCXXABI_LIBCXX_INCLUDES "${LIBCXXABI_LIBCXX_INCLUDES}" CACHE PATH + "Specify path to libc++ includes." FORCE) + +find_path( + LIBCXXABI_LIBCXX_PATH + utils/libcxx/test/__init__.py + PATHS ${LIBCXXABI_LIBCXX_PATH} + ${LIBCXXABI_LIBCXX_INCLUDES}/../ + ${LIBCXXABI_LIBCXX_SRC_DIRS} + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + +if (LIBCXXABI_LIBCXX_PATH STREQUAL "LIBCXXABI_LIBCXX_PATH-NOTFOUND") + message(WARNING "LIBCXXABI_LIBCXX_PATH was not specified and couldn't be infered.") + set(LIBCXXABI_LIBCXX_PATH "") +endif() + +set(LIBCXXABI_LIBCXX_PATH "${LIBCXXABI_LIBCXX_PATH}" CACHE PATH + "Specify path to libc++ source." FORCE) + +#=============================================================================== +# Configure System +#=============================================================================== + +# Add path for custom modules +set(CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules" + ${CMAKE_MODULE_PATH} + ) + +set(LIBCXXABI_COMPILER ${CMAKE_CXX_COMPILER}) +set(LIBCXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(LIBCXXABI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION + ${PACKAGE_VERSION}) + +if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) + set(DEFAULT_INSTALL_PREFIX lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/${LLVM_DEFAULT_TARGET_TRIPLE}/) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/${LLVM_DEFAULT_TARGET_TRIPLE}/lib${LIBCXXABI_LIBDIR_SUFFIX}) +elseif(LLVM_LIBRARY_OUTPUT_INTDIR) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) +else() + set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) +endif() + +set(LIBCXXABI_INSTALL_PREFIX ${DEFAULT_INSTALL_PREFIX} CACHE STRING + "Define libc++abi destination prefix.") + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) + +# By default, for non-standalone builds, libcxx and libcxxabi share a library +# directory. +if (NOT LIBCXXABI_LIBCXX_LIBRARY_PATH) + set(LIBCXXABI_LIBCXX_LIBRARY_PATH "${LIBCXXABI_LIBRARY_DIR}" CACHE PATH + "The path to libc++ library.") +endif() + +# Check that we can build with 32 bits if requested. +if (CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32) + if (LIBCXXABI_BUILD_32_BITS AND NOT LLVM_BUILD_32_BITS) # Don't duplicate the output from LLVM + message(STATUS "Building 32 bits executables and libraries.") + endif() +elseif(LIBCXXABI_BUILD_32_BITS) + message(FATAL_ERROR "LIBCXXABI_BUILD_32_BITS=ON is not supported on this platform.") +endif() + +# Declare libc++abi configuration variables. +# They are intended for use as follows: +# LIBCXXABI_C_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_CXX_FLAGS: General flags for both the c++ compiler and linker. +# LIBCXXABI_COMPILE_FLAGS: Compile only flags. +# LIBCXXABI_LINK_FLAGS: Linker only flags. +# LIBCXXABI_LIBRARIES: libraries libc++abi is linked to. + +set(LIBCXXABI_C_FLAGS "") +set(LIBCXXABI_CXX_FLAGS "") +set(LIBCXXABI_COMPILE_FLAGS "") +set(LIBCXXABI_LINK_FLAGS "") +set(LIBCXXABI_LIBRARIES "") + +# Include macros for adding and removing libc++abi flags. +include(HandleLibcxxabiFlags) + +#=============================================================================== +# Setup Compiler Flags +#=============================================================================== + +# Configure target flags +add_target_flags_if(LIBCXXABI_BUILD_32_BITS "-m32") +add_target_flags_if(LIBCXXABI_TARGET_TRIPLE + "--target=${LIBCXXABI_TARGET_TRIPLE}") +add_target_flags_if(LIBCXXABI_GCC_TOOLCHAIN + "--gcc-toolchain=${LIBCXXABI_GCC_TOOLCHAIN}") +add_target_flags_if(LIBCXXABI_SYSROOT + "--sysroot=${LIBCXXABI_SYSROOT}") + +if (LIBCXXABI_TARGET_TRIPLE) + set(TARGET_TRIPLE "${LIBCXXABI_TARGET_TRIPLE}") +endif() + +# Configure compiler. Must happen after setting the target flags. +include(config-ix) + +if (LIBCXXABI_HAS_NOSTDINCXX_FLAG) + list(APPEND LIBCXXABI_COMPILE_FLAGS -nostdinc++) + # Remove -stdlib flags to prevent them from causing an unused flag warning. + string(REPLACE "-stdlib=libc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-stdlib=libstdc++" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +endif() + +if (LIBCXXABI_USE_COMPILER_RT) + list(APPEND LIBCXXABI_LINK_FLAGS "-rtlib=compiler-rt") +endif() + +# Let the library headers know they are currently being used to build the +# library. +add_definitions(-D_LIBCXXABI_BUILDING_LIBRARY) + +# Disable DLL annotations on Windows for static builds. +if (WIN32 AND LIBCXXABI_ENABLE_STATIC AND NOT LIBCXXABI_ENABLE_SHARED) + add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) +endif() + +add_compile_flags_if_supported(-Werror=return-type) + +# Get warning flags +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) + add_compile_flags_if_supported(-Werror) + add_compile_flags_if_supported(-WX) +else() + add_compile_flags_if_supported(-Wno-error) + add_compile_flags_if_supported(-WX-) +endif() +if (LIBCXXABI_ENABLE_PEDANTIC) + add_compile_flags_if_supported(-pedantic) +endif() + +# Get feature flags. +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. + 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) + add_compile_flags_if_supported(-fno-exceptions) + add_compile_flags_if_supported(-EHs-) + add_compile_flags_if_supported(-EHa-) +endif() + +# Assert +string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE) +if (LIBCXXABI_ENABLE_ASSERTIONS) + # MSVC doesn't like _DEBUG on release builds. See PR 4379. + if (NOT MSVC) + list(APPEND LIBCXXABI_COMPILE_FLAGS -D_DEBUG) + endif() + # On Release builds cmake automatically defines NDEBUG, so we + # explicitly undefine it: + if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + list(APPEND LIBCXXABI_COMPILE_FLAGS -UNDEBUG) + endif() +else() + if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE") + list(APPEND LIBCXXABI_COMPILE_FLAGS -DNDEBUG) + endif() +endif() +# Static library +if (NOT LIBCXXABI_ENABLE_SHARED) + list(APPEND LIBCXXABI_COMPILE_FLAGS -D_LIBCPP_BUILD_STATIC) +endif() + +# Threading +if (NOT LIBCXXABI_ENABLE_THREADS) + if (LIBCXXABI_HAS_PTHREAD_API) + message(FATAL_ERROR "LIBCXXABI_HAS_PTHREAD_API can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() + if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + message(FATAL_ERROR "LIBCXXABI_HAS_EXTERNAL_THREAD_API can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() + if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) + message(FATAL_ERROR "LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY can only" + " be set to ON when LIBCXXABI_ENABLE_THREADS" + " is also set to ON.") + endif() + add_definitions(-D_LIBCXXABI_HAS_NO_THREADS) +endif() + +if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + if (LIBCXXABI_HAS_PTHREAD_API) + message(FATAL_ERROR "The options LIBCXXABI_HAS_EXTERNAL_THREAD_API" + " and LIBCXXABI_HAS_PTHREAD_API cannot be both" + " set to ON at the same time.") + endif() + if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) + message(FATAL_ERROR "The options LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY" + " and LIBCXXABI_HAS_EXTERNAL_THREAD_API cannot be both" + " set to ON at the same time.") + endif() +endif() + +if (LLVM_ENABLE_MODULES) + # Ignore that the rest of the modules flags are now unused. + add_compile_flags_if_supported(-Wno-unused-command-line-argument) + add_compile_flags(-fno-modules) +endif() + +set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS OFF) +if ((NOT LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) + OR (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXXABI_ENABLE_SHARED) + OR MINGW) + set(LIBCXXABI_HAS_UNDEFINED_SYMBOLS ON) +endif() + +if (LIBCXXABI_HAS_UNDEFINED_SYMBOLS) + # Need to allow unresolved symbols if this is to work with shared library builds + if (APPLE) + list(APPEND LIBCXXABI_LINK_FLAGS "-undefined dynamic_lookup") + else() + # Relax this restriction from HandleLLVMOptions + string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") + endif() +endif() + +if (LIBCXXABI_HAS_PTHREAD_API) + add_definitions(-D_LIBCPP_HAS_THREAD_API_PTHREAD) +endif() + +if (LIBCXXABI_HAS_EXTERNAL_THREAD_API) + add_definitions(-D_LIBCPP_HAS_THREAD_API_EXTERNAL) +endif() + +if (LIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY) + add_definitions(-D_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) +endif() + +# Prevent libc++abi from having library dependencies on libc++ +add_definitions(-D_LIBCPP_DISABLE_EXTERN_TEMPLATE) + +# Bring back `std::unexpected`, which is removed in C++17, to support +# pre-C++17. +add_definitions(-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) + +if (MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +# Define LIBCXXABI_USE_LLVM_UNWINDER for conditional compilation. +if (LIBCXXABI_USE_LLVM_UNWINDER) + add_definitions(-DLIBCXXABI_USE_LLVM_UNWINDER) +endif() + +if (LIBCXXABI_SILENT_TERMINATE) + add_definitions(-DLIBCXXABI_SILENT_TERMINATE) +endif() + +if (LIBCXXABI_BAREMETAL) + add_definitions(-DLIBCXXABI_BAREMETAL) +endif() + +string(REPLACE ";" " " LIBCXXABI_CXX_FLAGS "${LIBCXXABI_CXX_FLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBCXXABI_CXX_FLAGS}") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBCXXABI_C_FLAGS}") + +#=============================================================================== +# Setup Source Code +#=============================================================================== + +set(LIBCXXABI_LIBUNWIND_INCLUDES "${LIBCXXABI_LIBUNWIND_INCLUDES}" CACHE PATH + "Specify path to libunwind includes." FORCE) +set(LIBCXXABI_LIBUNWIND_PATH "${LIBCXXABI_LIBUNWIND_PATH}" CACHE PATH + "Specify path to libunwind source." FORCE) + +include_directories(include) +if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) + find_path( + LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL + libunwind.h + PATHS ${LIBCXXABI_LIBUNWIND_INCLUDES} + ${LIBCXXABI_LIBUNWIND_PATH}/include + ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBUNWIND_INCLUDES} + ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include + ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/include + ${LLVM_MAIN_SRC_DIR}/../libunwind/include + NO_DEFAULT_PATH + NO_CMAKE_FIND_ROOT_PATH + ) + + if (LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL-NOTFOUND") + set(LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL "") + endif() + + if (NOT LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL STREQUAL "") + include_directories("${LIBCXXABI_LIBUNWIND_INCLUDES_INTERNAL}") + endif() +endif() + +# Add source code. This also contains all of the logic for deciding linker flags +# soname, etc... +add_subdirectory(src) + +if (LIBCXXABI_INCLUDE_TESTS) + if (LIBCXXABI_STANDALONE_BUILD AND NOT LIBCXXABI_ENABLE_SHARED) + # We can't reasonably test the system C++ library with a static + # libc++abi. We either need to be able to replace libc++abi at + # run time (with a shared libc++abi), or we need to be able to + # replace the C++ runtime (with a non- standalone build). + message(WARNING "The libc++abi tests aren't valid when libc++abi " + "is built standalone (i.e. outside of " + "llvm/projects/libcxxabi ) and is built without " + "a shared library. Either build a shared " + "library, build libc++abi at the same time as " + "you build libc++, or do without testing. No " + "check target will be available!") + else() + add_subdirectory(test) + add_subdirectory(fuzz) + endif() +endif() diff --git a/CREDITS.TXT b/CREDITS.TXT new file mode 100644 index 000000000..fbb6cbf38 --- /dev/null +++ b/CREDITS.TXT @@ -0,0 +1,71 @@ +This file is a partial list of people who have contributed to the LLVM/libc++abi +project. If you have contributed a patch or made some other contribution to +LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be +done! + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Aaron Ballman +E: aaron@aaronballman.com +D: Minor patches + +N: Logan Chien +E: logan.chien@mediatek.com +D: ARM EHABI Unwind & Exception Handling + +N: Marshall Clow +E: mclow.lists@gmail.com +E: marshall@idio.com +D: Architect and primary coauthor of libc++abi + +N: Matthew Dempsky +E: matthew@dempsky.org +D: Minor patches and bug fixes. + +N: Nowar Gu +E: wenhan.gu@gmail.com +D: Minor patches and fixes + +N: Howard Hinnant +E: hhinnant@apple.com +D: Architect and primary coauthor of libc++abi + +N: Dana Jansens +E: danakj@chromium.org +D: ARM EHABI Unwind & Exception Handling + +N: Nick Kledzik +E: kledzik@apple.com + +N: Antoine Labour +E: piman@chromium.org +D: ARM EHABI Unwind & Exception Handling + +N: Bruce Mitchener, Jr. +E: bruce.mitchener@gmail.com +D: Minor typo fixes + +N: Andrew Morrow +E: andrew.c.morrow@gmail.com +D: Minor patches and fixes + +N: Erik Olofsson +E: erik.olofsson@hansoft.se +E: erik@olofsson.info +D: Minor patches and fixes + +N: Jon Roelofs +E: jroelofs@jroelofs.com +D: ARM EHABI Unwind & Exception Handling, Bare-metal + +N: Nico Weber +E: thakis@chromium.org +D: ARM EHABI Unwind & Exception Handling + +N: Albert J. Wong +E: ajwong@google.com +D: ARM EHABI Unwind & Exception Handling + diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 000000000..f1f163f38 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,76 @@ +============================================================================== +libc++abi License +============================================================================== + +The libc++abi library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake new file mode 100644 index 000000000..945de5850 --- /dev/null +++ b/cmake/Modules/HandleCompilerRT.cmake @@ -0,0 +1,61 @@ +function(find_compiler_rt_library name dest) + if (NOT DEFINED LIBCXXABI_COMPILE_FLAGS) + message(FATAL_ERROR "LIBCXXABI_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET) + list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}") + endif() + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") + message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") + set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt library") + endif() +endfunction() + +function(find_compiler_rt_dir dest) + if (NOT DEFINED LIBCXXABI_COMPILE_FLAGS) + message(FATAL_ERROR "LIBCXXABI_COMPILE_FLAGS must be defined when using this function") + endif() + set(dest "" PARENT_SCOPE) + if (APPLE) + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} + "-print-file-name=lib") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_DIR + ) + string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) + file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) + set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") + else() + set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} + "--rtlib=compiler-rt" "--print-libgcc-file-name") + execute_process( + COMMAND ${CLANG_COMMAND} + RESULT_VARIABLE HAD_ERROR + OUTPUT_VARIABLE LIBRARY_FILE + ) + string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) + get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) + endif() + if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}") + message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}") + set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE) + else() + message(STATUS "Failed to find compiler-rt directory") + endif() +endfunction() diff --git a/cmake/Modules/HandleLibcxxabiFlags.cmake b/cmake/Modules/HandleLibcxxabiFlags.cmake new file mode 100644 index 000000000..3eddd7bdc --- /dev/null +++ b/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/cmake/Modules/HandleOutOfTreeLLVM.cmake b/cmake/Modules/HandleOutOfTreeLLVM.cmake new file mode 100644 index 000000000..e50d0262f --- /dev/null +++ b/cmake/Modules/HandleOutOfTreeLLVM.cmake @@ -0,0 +1,140 @@ +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_FROM_LLVM_CONFIG) + file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG}" LLVM_CMAKE_PATH) + else() + file(TO_CMAKE_PATH "${LLVM_BINARY_DIR}" LLVM_BINARY_DIR_CMAKE_STYLE) + set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/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() + + # In a standalone build, we don't have llvm to automatically generate the + # llvm-lit script for us. So we need to provide an explicit directory that + # the configurator should write the script into. + set(LLVM_LIT_OUTPUT_DIR "${libcxxabi_BINARY_DIR}/bin") + + if (LLVM_INCLUDE_TESTS) + # Required LIT Configuration ------------------------------------------------ + # Define the default arguments to use with 'lit', and an option for the user + # to override. + set(LLVM_EXTERNAL_LIT "${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py") + 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") + endif() + + # 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/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake new file mode 100644 index 000000000..e75002bd8 --- /dev/null +++ b/cmake/Modules/MacroEnsureOutOfSourceBuild.cmake @@ -0,0 +1,18 @@ +# MACRO_ENSURE_OUT_OF_SOURCE_BUILD() + +macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage ) + +string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource ) +if( _insource ) + message( SEND_ERROR "${_errorMessage}" ) + message( FATAL_ERROR + "In-source builds are not allowed. + CMake would overwrite the makefiles distributed with libcxxabi. + Please create a directory and run cmake from there, passing the path + to this source directory as the last argument. + This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. + Please delete them." + ) +endif( _insource ) + +endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD ) diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake new file mode 100644 index 000000000..379b55477 --- /dev/null +++ b/cmake/config-ix.cmake @@ -0,0 +1,89 @@ +include(CheckLibraryExists) +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + +check_library_exists(c fopen "" LIBCXXABI_HAS_C_LIB) +if (NOT LIBCXXABI_USE_COMPILER_RT) + check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXXABI_HAS_GCC_S_LIB) +endif () + +# libc++abi is built with -nodefaultlibs, so we want all our checks to also +# use this option, otherwise we may end up with an inconsistency between +# the flags we think we require during configuration (if the checks are +# performed without -nodefaultlibs) and the flags that are actually +# required during compilation (which has the -nodefaultlibs). libc is +# required for the link to go through. We remove sanitizers from the +# configuration checks to avoid spurious link errors. +check_c_compiler_flag(-nodefaultlibs LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) +if (LIBCXXABI_HAS_NODEFAULTLIBS_FLAG) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -nodefaultlibs") + if (LIBCXXABI_HAS_C_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES c) + endif () + if (LIBCXXABI_USE_COMPILER_RT) + list(APPEND CMAKE_REQUIRED_FLAGS -rtlib=compiler-rt) + find_compiler_rt_library(builtins LIBCXXABI_BUILTINS_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBCXXABI_BUILTINS_LIBRARY}") + elseif (LIBCXXABI_HAS_GCC_S_LIB) + list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s) + endif () + if (MINGW) + # Mingw64 requires quite a few "C" runtime libraries in order for basic + # programs to link successfully with -nodefaultlibs. + if (LIBCXXABI_USE_COMPILER_RT) + set(MINGW_RUNTIME ${LIBCXXABI_BUILTINS_LIBRARY}) + else () + set(MINGW_RUNTIME gcc_s gcc) + endif() + set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32 + shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME} + moldname mingwex msvcrt) + list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES}) + endif() + if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all") + endif () + if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters") + endif () +endif () + +# Check compiler flags +check_c_compiler_flag(-funwind-tables LIBCXXABI_HAS_FUNWIND_TABLES) +check_cxx_compiler_flag(-fno-exceptions LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG) +check_cxx_compiler_flag(-fno-rtti LIBCXXABI_HAS_NO_RTTI_FLAG) +check_cxx_compiler_flag(-fstrict-aliasing LIBCXXABI_HAS_FSTRICT_ALIASING_FLAG) +check_cxx_compiler_flag(-nostdinc++ LIBCXXABI_HAS_NOSTDINCXX_FLAG) +check_cxx_compiler_flag(-Wall LIBCXXABI_HAS_WALL_FLAG) +check_cxx_compiler_flag(-W LIBCXXABI_HAS_W_FLAG) +check_cxx_compiler_flag(-Wunused-function LIBCXXABI_HAS_WUNUSED_FUNCTION_FLAG) +check_cxx_compiler_flag(-Wunused-variable LIBCXXABI_HAS_WUNUSED_VARIABLE_FLAG) +check_cxx_compiler_flag(-Wunused-parameter LIBCXXABI_HAS_WUNUSED_PARAMETER_FLAG) +check_cxx_compiler_flag(-Wstrict-aliasing LIBCXXABI_HAS_WSTRICT_ALIASING_FLAG) +check_cxx_compiler_flag(-Wstrict-overflow LIBCXXABI_HAS_WSTRICT_OVERFLOW_FLAG) +check_cxx_compiler_flag(-Wwrite-strings LIBCXXABI_HAS_WWRITE_STRINGS_FLAG) +check_cxx_compiler_flag(-Wchar-subscripts LIBCXXABI_HAS_WCHAR_SUBSCRIPTS_FLAG) +check_cxx_compiler_flag(-Wmismatched-tags LIBCXXABI_HAS_WMISMATCHED_TAGS_FLAG) +check_cxx_compiler_flag(-Wmissing-braces LIBCXXABI_HAS_WMISSING_BRACES_FLAG) +check_cxx_compiler_flag(-Wshorten-64-to-32 LIBCXXABI_HAS_WSHORTEN_64_TO_32_FLAG) +check_cxx_compiler_flag(-Wsign-conversion LIBCXXABI_HAS_WSIGN_CONVERSION_FLAG) +check_cxx_compiler_flag(-Wsign-compare LIBCXXABI_HAS_WSIGN_COMPARE_FLAG) +check_cxx_compiler_flag(-Wshadow LIBCXXABI_HAS_WSHADOW_FLAG) +check_cxx_compiler_flag(-Wconversion LIBCXXABI_HAS_WCONVERSION_FLAG) +check_cxx_compiler_flag(-Wnewline-eof LIBCXXABI_HAS_WNEWLINE_EOF_FLAG) +check_cxx_compiler_flag(-Wundef LIBCXXABI_HAS_WUNDEF_FLAG) +check_cxx_compiler_flag(-pedantic LIBCXXABI_HAS_PEDANTIC_FLAG) +check_cxx_compiler_flag(-Werror LIBCXXABI_HAS_WERROR_FLAG) +check_cxx_compiler_flag(-Wno-error LIBCXXABI_HAS_WNO_ERROR_FLAG) +check_cxx_compiler_flag(/WX LIBCXXABI_HAS_WX_FLAG) +check_cxx_compiler_flag(/WX- LIBCXXABI_HAS_NO_WX_FLAG) +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 libraries +check_library_exists(dl dladdr "" LIBCXXABI_HAS_DL_LIB) +check_library_exists(pthread pthread_once "" LIBCXXABI_HAS_PTHREAD_LIB) +check_library_exists(c __cxa_thread_atexit_impl "" + LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 000000000..017427e46 --- /dev/null +++ b/fuzz/CMakeLists.txt @@ -0,0 +1,11 @@ +# See http://llvm.org/docs/LibFuzzer.html +if( LLVM_USE_SANITIZE_COVERAGE ) + add_executable(cxa_demangle_fuzzer + cxa_demangle_fuzzer.cpp + ../src/cxa_demangle.cpp + ) + + target_link_libraries(cxa_demangle_fuzzer + LLVMFuzzer + ) +endif() diff --git a/fuzz/cxa_demangle_fuzzer.cpp b/fuzz/cxa_demangle_fuzzer.cpp new file mode 100644 index 000000000..cc9b19367 --- /dev/null +++ b/fuzz/cxa_demangle_fuzzer.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include +extern "C" char * +__cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status); + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + char *str = new char[size+1]; + memcpy(str, data, size); + str[size] = 0; + free(__cxa_demangle(str, 0, 0, 0)); + delete [] str; + return 0; +} diff --git a/include/__cxxabi_config.h b/include/__cxxabi_config.h new file mode 100644 index 000000000..46f591447 --- /dev/null +++ b/include/__cxxabi_config.h @@ -0,0 +1,73 @@ +//===-------------------------- __cxxabi_config.h -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ____CXXABI_CONFIG_H +#define ____CXXABI_CONFIG_H + +#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ + !defined(__ARM_DWARF_EH__) +#define _LIBCXXABI_ARM_EHABI +#endif + +#if !defined(__has_attribute) +#define __has_attribute(_attribute_) 0 +#endif + +#if defined(_WIN32) + #if defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS + #define _LIBCXXABI_FUNC_VIS + #define _LIBCXXABI_TYPE_VIS + #elif defined(_LIBCXXABI_BUILDING_LIBRARY) + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS __declspec(dllexport) + #define _LIBCXXABI_FUNC_VIS __declspec(dllexport) + #define _LIBCXXABI_TYPE_VIS __declspec(dllexport) + #else + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS __declspec(dllimport) + #define _LIBCXXABI_FUNC_VIS __declspec(dllimport) + #define _LIBCXXABI_TYPE_VIS __declspec(dllimport) + #endif +#else + #if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS) + #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden"))) + #define _LIBCXXABI_DATA_VIS __attribute__((__visibility__("default"))) + #define _LIBCXXABI_FUNC_VIS __attribute__((__visibility__("default"))) + #if __has_attribute(__type_visibility__) + #define _LIBCXXABI_TYPE_VIS __attribute__((__type_visibility__("default"))) + #else + #define _LIBCXXABI_TYPE_VIS __attribute__((__visibility__("default"))) + #endif + #else + #define _LIBCXXABI_HIDDEN + #define _LIBCXXABI_DATA_VIS + #define _LIBCXXABI_FUNC_VIS + #define _LIBCXXABI_TYPE_VIS + #endif +#endif + +#if defined(_WIN32) +#define _LIBCXXABI_WEAK +#else +#define _LIBCXXABI_WEAK __attribute__((__weak__)) +#endif + +#if defined(__clang__) +#define _LIBCXXABI_COMPILER_CLANG +#endif + +#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG) +#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +#define _LIBCXXABI_NO_CFI +#endif + +#endif // ____CXXABI_CONFIG_H diff --git a/include/cxxabi.h b/include/cxxabi.h new file mode 100644 index 000000000..2596560d6 --- /dev/null +++ b/include/cxxabi.h @@ -0,0 +1,177 @@ +//===--------------------------- cxxabi.h ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __CXXABI_H +#define __CXXABI_H + +/* + * This header provides the interface to the C++ ABI as defined at: + * http://www.codesourcery.com/cxx-abi/ + */ + +#include +#include + +#include <__cxxabi_config.h> + +#define _LIBCPPABI_VERSION 1002 +#define _LIBCXXABI_NORETURN __attribute__((noreturn)) + +#ifdef __cplusplus + +namespace std { +#if defined(_WIN32) +class _LIBCXXABI_TYPE_VIS type_info; // forward declaration +#else +class type_info; // forward declaration +#endif +} + + +// runtime routines use C calling conventions, but are in __cxxabiv1 namespace +namespace __cxxabiv1 { +extern "C" { + +// 2.4.2 Allocating the Exception Object +extern _LIBCXXABI_FUNC_VIS void * +__cxa_allocate_exception(size_t thrown_size) throw(); +extern _LIBCXXABI_FUNC_VIS void +__cxa_free_exception(void *thrown_exception) throw(); + +// 2.4.3 Throwing the Exception Object +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void +__cxa_throw(void *thrown_exception, std::type_info *tinfo, + void (*dest)(void *)); + +// 2.5.3 Exception Handlers +extern _LIBCXXABI_FUNC_VIS void * +__cxa_get_exception_ptr(void *exceptionObject) throw(); +extern _LIBCXXABI_FUNC_VIS void * +__cxa_begin_catch(void *exceptionObject) throw(); +extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); +#if defined(_LIBCXXABI_ARM_EHABI) +extern _LIBCXXABI_FUNC_VIS bool +__cxa_begin_cleanup(void *exceptionObject) throw(); +extern _LIBCXXABI_FUNC_VIS void __cxa_end_cleanup(); +#endif +extern _LIBCXXABI_FUNC_VIS std::type_info *__cxa_current_exception_type(); + +// 2.5.4 Rethrowing Exceptions +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_rethrow(); + +// 2.6 Auxiliary Runtime APIs +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void); +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void +__cxa_throw_bad_array_new_length(void); + +// 3.2.6 Pure Virtual Function API +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_pure_virtual(void); + +// 3.2.7 Deleted Virtual Function API +extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_deleted_virtual(void); + +// 3.3.2 One-time Construction API +#ifdef __arm__ +extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint32_t *); +extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint32_t *); +extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint32_t *); +#else +extern _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(uint64_t *); +extern _LIBCXXABI_FUNC_VIS void __cxa_guard_release(uint64_t *); +extern _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(uint64_t *); +#endif + +// 3.3.3 Array Construction and Destruction API +extern _LIBCXXABI_FUNC_VIS void * +__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void *), void (*destructor)(void *)); + +extern _LIBCXXABI_FUNC_VIS void * +__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void *), void (*destructor)(void *), + void *(*alloc)(size_t), void (*dealloc)(void *)); + +extern _LIBCXXABI_FUNC_VIS void * +__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void *), void (*destructor)(void *), + void *(*alloc)(size_t), void (*dealloc)(void *, size_t)); + +extern _LIBCXXABI_FUNC_VIS void +__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size, + void (*constructor)(void *), void (*destructor)(void *)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address, + size_t element_count, + size_t element_size, + void (*destructor)(void *)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address, + size_t element_count, + size_t element_size, + void (*destructor)(void *)); + +extern _LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address, + size_t element_size, + size_t padding_size, + void (*destructor)(void *)); + +extern _LIBCXXABI_FUNC_VIS void +__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size, + void (*destructor)(void *), void (*dealloc)(void *)); + +extern _LIBCXXABI_FUNC_VIS void +__cxa_vec_delete3(void *__array_address, size_t element_size, + size_t padding_size, void (*destructor)(void *), + void (*dealloc)(void *, size_t)); + +extern _LIBCXXABI_FUNC_VIS void +__cxa_vec_cctor(void *dest_array, void *src_array, size_t element_count, + size_t element_size, void (*constructor)(void *, void *), + void (*destructor)(void *)); + +// 3.3.5.3 Runtime API +extern _LIBCXXABI_FUNC_VIS int __cxa_atexit(void (*f)(void *), void *p, + void *d); +extern _LIBCXXABI_FUNC_VIS int __cxa_finalize(void *); + +// 3.4 Demangler API +extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name, + char *output_buffer, + size_t *length, int *status); + +// Apple additions to support C++ 0x exception_ptr class +// These are primitives to wrap a smart pointer around an exception object +extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw(); +extern _LIBCXXABI_FUNC_VIS void +__cxa_rethrow_primary_exception(void *primary_exception); +extern _LIBCXXABI_FUNC_VIS void +__cxa_increment_exception_refcount(void *primary_exception) throw(); +extern _LIBCXXABI_FUNC_VIS void +__cxa_decrement_exception_refcount(void *primary_exception) throw(); + +// Apple extension to support std::uncaught_exception() +extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw(); +extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw(); + +#ifdef __linux__ +// Linux TLS support. Not yet an official part of the Itanium ABI. +// https://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables +extern _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(void (*)(void *), void *, + void *) throw(); +#endif + +} // extern "C" +} // namespace __cxxabiv1 + +namespace abi = __cxxabiv1; + +#endif // __cplusplus + +#endif // __CXXABI_H diff --git a/lib/buildit b/lib/buildit new file mode 100755 index 000000000..5a4a71090 --- /dev/null +++ b/lib/buildit @@ -0,0 +1,99 @@ +#! /bin/sh +# +# Set the $TRIPLE environment variable to your system's triple before +# running this script. If you set $CXX, that will be used to compile +# the library. Otherwise we'll use clang++. + +set -e + +if [ `basename $(pwd)` != "lib" ] +then + echo "current directory must be lib" + exit 1 +fi + +if [ -z "$CXX" ] +then + CXX=clang++ +fi + +if [ -z "$CC" ] +then + CC=clang +fi + +if [ -z $RC_ProjectSourceVersion ] +then + RC_ProjectSourceVersion=1 +fi + +EXTRA_FLAGS="-std=c++11 -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \ + -Wsign-conversion -Wshadow -Wconversion -Wunused-variable \ + -Wmissing-field-initializers -Wchar-subscripts -Wmismatched-tags \ + -Wmissing-braces -Wshorten-64-to-32 -Wsign-compare \ + -Wstrict-aliasing=2 -Wstrict-overflow=4 -Wunused-parameter \ + -Wnewline-eof" + +case $TRIPLE in + *-apple-*) + if [ -z $RC_XBS ] + then + RC_CFLAGS="-arch i386 -arch x86_64" + fi + SOEXT=dylib + if [ -n "$SDKROOT" ] + then + EXTRA_FLAGS+="-isysroot ${SDKROOT}" + CXX=`xcrun -sdk "${SDKROOT}" -find clang++` + CC=`xcrun -sdk "${SDKROOT}" -find clang` + fi + LDSHARED_FLAGS="-o libc++abi.dylib \ + -dynamiclib -nodefaultlibs \ + -current_version ${RC_ProjectSourceVersion} \ + -compatibility_version 1 \ + -install_name /usr/lib/libc++abi.dylib \ + -lSystem" + if [ -f "${SDKROOT}/usr/local/lib/libCrashReporterClient.a" ] + then + LDSHARED_FLAGS+=" -lCrashReporterClient" + fi + ;; + *-*-mingw*) + # FIXME: removing libgcc and libsupc++ dependencies means porting libcxxrt and LLVM/compiler-rt + SOEXT=dll + LDSHARED_FLAGS="-o libc++abi.dll \ + -shared -nodefaultlibs -Wl,--export-all-symbols -Wl,--allow-multiple-definition -Wl,--out-implib,libc++abi.dll.a \ + -lsupc++ -lpthread -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcr100 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt" + ;; + *) + RC_CFLAGS="-fPIC" + SOEXT=so + LDSHARED_FLAGS="-o libc++abi.so.1.0 \ + -shared -nodefaultlibs -Wl,-soname,libc++abi.so.1 \ + -lpthread -lrt -lc -lstdc++" + ;; +esac + +if [ -z $RC_XBS ] +then + rm -f libc++abi.1.$SOEXT* +fi + +set -x + +for FILE in ../src/*.cpp; do + $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE +done +case $TRIPLE in + *-*-mingw*) + for FILE in ../src/support/win32/*.cpp; do + $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE + done + ;; +esac +$CC *.o $RC_CFLAGS $LDSHARED_FLAGS $EXTRA_FLAGS + +if [ -z $RC_XBS ] +then + rm *.o +fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..776c51294 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,218 @@ +# Get sources +set(LIBCXXABI_SOURCES + # C++ABI files + cxa_aux_runtime.cpp + cxa_default_handlers.cpp + cxa_demangle.cpp + cxa_exception_storage.cpp + cxa_guard.cpp + cxa_handlers.cpp + cxa_unexpected.cpp + cxa_vector.cpp + cxa_virtual.cpp + # C++ STL files + stdlib_exception.cpp + stdlib_stdexcept.cpp + stdlib_typeinfo.cpp + # Internal files + abort_message.cpp + fallback_malloc.cpp + private_typeinfo.cpp +) + +if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) + list(APPEND LIBCXXABI_SOURCES stdlib_new_delete.cpp) +endif() + +if (LIBCXXABI_ENABLE_EXCEPTIONS) + list(APPEND LIBCXXABI_SOURCES cxa_exception.cpp) + list(APPEND LIBCXXABI_SOURCES cxa_personality.cpp) +else() + list(APPEND LIBCXXABI_SOURCES cxa_noexception.cpp) +endif() + +if (LIBCXXABI_ENABLE_THREADS AND UNIX AND NOT (APPLE OR CYGWIN)) + list(APPEND LIBCXXABI_SOURCES cxa_thread_atexit.cpp) +endif() + +set(LIBCXXABI_HEADERS ../include/cxxabi.h) + +# Add all the headers to the project for IDEs. +if (MSVC_IDE OR XCODE) + # Force them all into the headers dir on MSVC, otherwise they end up at + # project scope because they don't have extensions. + if (MSVC_IDE) + source_group("Header Files" FILES ${LIBCXXABI_HEADERS}) + endif() +endif() + +include_directories("${LIBCXXABI_LIBCXX_INCLUDES}") + +if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) + add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) +endif() + +if (LIBCXXABI_ENABLE_THREADS) + add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) +endif() + +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_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) + list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_shared) + elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) + list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_static) + else() + list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind) + endif() + if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) + list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind_shared) + elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) + # We handle this by directly merging libunwind objects into libc++abi. + else() + list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind) + endif() +else() + add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) +endif() +if (MINGW) + # MINGW_LIBRARIES is defined in config-ix.cmake + list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) +endif() + +# Setup flags. +add_link_flags_if_supported(-nodefaultlibs) + +set(LIBCXXABI_SHARED_LINK_FLAGS) + +if ( APPLE ) + if ( CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6" ) + list(APPEND LIBCXXABI_COMPILE_FLAGS "-U__STRICT_ANSI__") + list(APPEND LIBCXXABI_SHARED_LINK_FLAGS + "-compatibility_version 1" + "-current_version 1" + "-install_name /usr/lib/libc++abi.1.dylib") + list(APPEND LIBCXXABI_LINK_FLAGS + "/usr/lib/libSystem.B.dylib") + else() + list(APPEND LIBCXXABI_SHARED_LINK_FLAGS + "-compatibility_version 1" + "-install_name /usr/lib/libc++abi.1.dylib") + endif() +endif() + +split_list(LIBCXXABI_COMPILE_FLAGS) +split_list(LIBCXXABI_LINK_FLAGS) +split_list(LIBCXXABI_SHARED_LINK_FLAGS) + +# FIXME: libc++abi.so will not link when modules are enabled because it depends +# on symbols defined in libc++.so which has not yet been built. +if (LLVM_ENABLE_MODULES) + string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") +endif() + +# Add a object library that contains the compiled source files. +add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) +set_target_properties(cxxabi_objects + PROPERTIES + CXX_EXTENSIONS + OFF + CXX_STANDARD + 11 + CXX_STANDARD_REQUIRED + ON + COMPILE_FLAGS + "${LIBCXXABI_COMPILE_FLAGS}" + POSITION_INDEPENDENT_CODE + ON) + +# Build the shared library. +if (LIBCXXABI_ENABLE_SHARED) + add_library(cxxabi_shared SHARED $) + if(COMMAND llvm_setup_rpath) + llvm_setup_rpath(cxxabi_shared) + endif() + target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_SHARED_LIBRARIES}) + set_target_properties(cxxabi_shared + 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_BUILD_TARGETS "cxxabi_shared") + if (LIBCXXABI_INSTALL_SHARED_LIBRARY) + list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared") + endif() +endif() + +# Build the static library. +if (LIBCXXABI_ENABLE_STATIC) + set(cxxabi_static_sources $) + if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) + if (TARGET unwind_static OR HAVE_LIBUNWIND) + list(APPEND cxxabi_static_sources $) + endif() + endif() + add_library(cxxabi_static STATIC ${cxxabi_static_sources}) + target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_STATIC_LIBRARIES}) + set_target_properties(cxxabi_static + 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_BUILD_TARGETS "cxxabi_static") + if (LIBCXXABI_INSTALL_STATIC_LIBRARY) + list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_static") + endif() +endif() + +# Add a meta-target for both libraries. +add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS}) + +if (LIBCXXABI_INSTALL_LIBRARY) + install(TARGETS ${LIBCXXABI_INSTALL_TARGETS} + LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi + ) +endif() + +if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY) + add_custom_target(install-cxxabi + DEPENDS cxxabi + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=cxxabi + -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") + add_custom_target(install-cxxabi-stripped + DEPENDS cxxabi + COMMAND "${CMAKE_COMMAND}" + -DCMAKE_INSTALL_COMPONENT=cxxabi + -DCMAKE_INSTALL_DO_STRIP=1 + -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") + + # TODO: This is a legacy target name and should be removed at some point. + add_custom_target(install-libcxxabi DEPENDS install-cxxabi) +endif() diff --git a/src/abort_message.cpp b/src/abort_message.cpp new file mode 100644 index 000000000..7a2a9f835 --- /dev/null +++ b/src/abort_message.cpp @@ -0,0 +1,78 @@ +//===------------------------- abort_message.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include "abort_message.h" + +#ifdef __BIONIC__ +#include +#if __ANDROID_API__ >= 21 +#include +extern "C" void android_set_abort_message(const char* msg); +#else +#include +#endif // __ANDROID_API__ >= 21 +#endif // __BIONIC__ + +#ifdef __APPLE__ +# if defined(__has_include) && __has_include() +# define HAVE_CRASHREPORTERCLIENT_H +# include +# endif +#endif + +void abort_message(const char* format, ...) +{ + // write message to stderr +#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) +#ifdef __APPLE__ + fprintf(stderr, "libc++abi.dylib: "); +#endif + va_list list; + va_start(list, format); + vfprintf(stderr, format, list); + va_end(list); + fprintf(stderr, "\n"); +#endif + +#if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H) + // record message in crash report + char* buffer; + va_list list2; + va_start(list2, format); + vasprintf(&buffer, format, list2); + va_end(list2); + CRSetCrashLogMessage(buffer); +#elif defined(__BIONIC__) + char* buffer; + va_list list2; + va_start(list2, format); + vasprintf(&buffer, format, list2); + va_end(list2); + +#if __ANDROID_API__ >= 21 + // Show error in tombstone. + android_set_abort_message(buffer); + + // Show error in logcat. + openlog("libc++abi", 0, 0); + syslog(LOG_CRIT, "%s", buffer); + closelog(); +#else + // The good error reporting wasn't available in Android until L. Since we're + // about to abort anyway, just call __assert2, which will log _somewhere_ + // (tombstone and/or logcat) in older releases. + __assert2(__FILE__, __LINE__, __func__, buffer); +#endif // __ANDROID_API__ >= 21 +#endif // __BIONIC__ + + abort(); +} diff --git a/src/abort_message.h b/src/abort_message.h new file mode 100644 index 000000000..e8f9571cb --- /dev/null +++ b/src/abort_message.h @@ -0,0 +1,27 @@ +//===-------------------------- abort_message.h-----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __ABORT_MESSAGE_H_ +#define __ABORT_MESSAGE_H_ + +#include "cxxabi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void +abort_message(const char *format, ...) __attribute__((format(printf, 1, 2))); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/cxa_aux_runtime.cpp b/src/cxa_aux_runtime.cpp new file mode 100644 index 000000000..878d3bd03 --- /dev/null +++ b/src/cxa_aux_runtime.cpp @@ -0,0 +1,44 @@ +//===------------------------ cxa_aux_runtime.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Auxiliary Runtime APIs" +// http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-aux +//===----------------------------------------------------------------------===// + +#include "cxxabi.h" +#include +#include + +namespace __cxxabiv1 { +extern "C" { +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) { +#ifndef _LIBCXXABI_NO_EXCEPTIONS + throw std::bad_cast(); +#else + std::terminate(); +#endif +} + +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { +#ifndef _LIBCXXABI_NO_EXCEPTIONS + throw std::bad_typeid(); +#else + std::terminate(); +#endif +} + +_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void +__cxa_throw_bad_array_new_length(void) { +#ifndef _LIBCXXABI_NO_EXCEPTIONS + throw std::bad_array_new_length(); +#else + std::terminate(); +#endif +} +} // extern "C" +} // abi diff --git a/src/cxa_default_handlers.cpp b/src/cxa_default_handlers.cpp new file mode 100644 index 000000000..0fa169f06 --- /dev/null +++ b/src/cxa_default_handlers.cpp @@ -0,0 +1,126 @@ +//===------------------------- cxa_default_handlers.cpp -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the default terminate_handler and unexpected_handler. +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include "abort_message.h" +#include "cxxabi.h" +#include "cxa_handlers.hpp" +#include "cxa_exception.hpp" +#include "private_typeinfo.h" +#include "include/atomic_support.h" + +#if !defined(LIBCXXABI_SILENT_TERMINATE) +static const char* cause = "uncaught"; + +__attribute__((noreturn)) +static void demangling_terminate_handler() +{ + // If there might be an uncaught exception + using namespace __cxxabiv1; + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (globals) + { + __cxa_exception* exception_header = globals->caughtExceptions; + // If there is an uncaught exception + if (exception_header) + { + _Unwind_Exception* unwind_exception = + reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; + bool native_exception = + (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + if (native_exception) + { + void* thrown_object = + unwind_exception->exception_class == kOurDependentExceptionClass ? + ((__cxa_dependent_exception*)exception_header)->primaryException : + exception_header + 1; + const __shim_type_info* thrown_type = + static_cast(exception_header->exceptionType); + // Try to get demangled name of thrown_type + int status; + char buf[1024]; + size_t len = sizeof(buf); + const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); + if (status != 0) + name = thrown_type->name(); + // If the uncaught exception can be caught with std::exception& + const __shim_type_info* catch_type = + static_cast(&typeid(std::exception)); + if (catch_type->can_catch(thrown_type, thrown_object)) + { + // Include the what() message from the exception + const std::exception* e = static_cast(thrown_object); + abort_message("terminating with %s exception of type %s: %s", + cause, name, e->what()); + } + else + // Else just note that we're terminating with an exception + abort_message("terminating with %s exception of type %s", + cause, name); + } + else + // Else we're terminating with a foreign exception + abort_message("terminating with %s foreign exception", cause); + } + } + // Else just note that we're terminating + abort_message("terminating"); +} + +__attribute__((noreturn)) +static void demangling_unexpected_handler() +{ + cause = "unexpected"; + std::terminate(); +} + +static std::terminate_handler default_terminate_handler = demangling_terminate_handler; +static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler; +#else +static std::terminate_handler default_terminate_handler = std::abort; +static std::terminate_handler default_unexpected_handler = std::terminate; +#endif + +// +// Global variables that hold the pointers to the current handler +// +_LIBCXXABI_DATA_VIS +std::terminate_handler __cxa_terminate_handler = default_terminate_handler; + +_LIBCXXABI_DATA_VIS +std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; + +namespace std +{ + +unexpected_handler +set_unexpected(unexpected_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_unexpected_handler; + return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func, + _AO_Acq_Rel); +} + +terminate_handler +set_terminate(terminate_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_terminate_handler; + return __libcpp_atomic_exchange(&__cxa_terminate_handler, func, + _AO_Acq_Rel); +} + +} diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp new file mode 100644 index 000000000..1007d7efa --- /dev/null +++ b/src/cxa_demangle.cpp @@ -0,0 +1,4998 @@ +//===-------------------------- cxa_demangle.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// FIXME: (possibly) incomplete list of features that clang mangles that this +// file does not yet support: +// - C++ modules TS + +#define _LIBCPP_NO_EXCEPTIONS + +#include "__cxxabi_config.h" + +#include "demangle/Compiler.h" +#include "demangle/StringView.h" +#include "demangle/Utility.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +enum : int { + demangle_unknown_error = -4, + demangle_invalid_args = -3, + demangle_invalid_mangled_name = -2, + demangle_memory_alloc_failure = -1, + demangle_success = 0, +}; + +// 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 { + KNodeArrayNode, + KDotSuffix, + KVendorExtQualType, + KQualType, + KConversionOperatorType, + KPostfixQualifiedType, + KElaboratedTypeSpefType, + KNameType, + KAbiTagAttr, + KEnableIfAttr, + KObjCProtoName, + KPointerType, + KReferenceType, + KPointerToMemberType, + KArrayType, + KFunctionType, + KNoexceptSpec, + KDynamicExceptionSpec, + KFunctionEncoding, + KLiteralOperator, + KSpecialName, + KCtorVtableSpecialName, + KQualifiedName, + KNestedName, + KLocalName, + KVectorType, + KParameterPack, + KTemplateArgumentPack, + KParameterPackExpansion, + KTemplateArgs, + KForwardTemplateReference, + KNameWithTemplateArgs, + KGlobalQualifiedName, + KStdQualifiedName, + KExpandedSpecialSubstitution, + KSpecialSubstitution, + KCtorDtorName, + KDtorName, + KUnnamedTypeName, + KClosureTypeName, + KStructuredBindingName, + KExpr, + KBracedExpr, + KBracedRangeExpr, + }; + + Kind K; + + /// Three-way bool to track a cached value. Unknown is possible if this node + /// has an unexpanded parameter pack below it that may affect this cache. + enum class Cache : unsigned char { Yes, No, Unknown, }; + + /// Tracks if this node has a component on its right side, in which case we + /// need to call printRight. + Cache RHSComponentCache; + + /// Track if this node is a (possibly qualified) array type. This can affect + /// how we format the output string. + Cache ArrayCache; + + /// Track if this node is a (possibly qualified) function type. This can + /// affect how we format the output string. + Cache FunctionCache; + + Node(Kind K_, Cache RHSComponentCache_ = Cache::No, + Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) + : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), + FunctionCache(FunctionCache_) {} + + bool hasRHSComponent(OutputStream &S) const { + if (RHSComponentCache != Cache::Unknown) + return RHSComponentCache == Cache::Yes; + return hasRHSComponentSlow(S); + } + + bool hasArray(OutputStream &S) const { + if (ArrayCache != Cache::Unknown) + return ArrayCache == Cache::Yes; + return hasArraySlow(S); + } + + bool hasFunction(OutputStream &S) const { + if (FunctionCache != Cache::Unknown) + return FunctionCache == Cache::Yes; + return hasFunctionSlow(S); + } + + Kind getKind() const { return K; } + + virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } + virtual bool hasArraySlow(OutputStream &) const { return false; } + virtual bool hasFunctionSlow(OutputStream &) const { return false; } + + // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to + // get at a node that actually represents some concrete syntax. + virtual const Node *getSyntaxNode(OutputStream &) const { + return this; + } + + void print(OutputStream &S) const { + printLeft(S); + if (RHSComponentCache != Cache::No) + 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 + // implementation. + virtual void printRight(OutputStream &) const {} + + virtual StringView getBaseName() const { return StringView(); } + + // Silence compiler warnings, this dtor will never be called. + virtual ~Node() = default; + +#ifndef NDEBUG + DUMP_METHOD void dump() const { + char *Buffer = static_cast(std::malloc(1024)); + OutputStream S(Buffer, 1024); + print(S); + S += '\0'; + printf("Symbol dump for %p: %s\n", (const void*)this, S.getBuffer()); + std::free(S.getBuffer()); + } +#endif +}; + +class NodeArray { + Node **Elements; + size_t NumElements; + +public: + NodeArray() : Elements(nullptr), NumElements(0) {} + NodeArray(Node **Elements_, size_t NumElements_) + : Elements(Elements_), NumElements(NumElements_) {} + + bool empty() const { return NumElements == 0; } + size_t size() const { return NumElements; } + + Node **begin() const { return Elements; } + Node **end() const { return Elements + NumElements; } + + Node *operator[](size_t Idx) const { return Elements[Idx]; } + + void printWithComma(OutputStream &S) const { + bool FirstElement = true; + for (size_t Idx = 0; Idx != NumElements; ++Idx) { + size_t BeforeComma = S.getCurrentPosition(); + if (!FirstElement) + S += ", "; + size_t AfterComma = S.getCurrentPosition(); + Elements[Idx]->print(S); + + // Elements[Idx] is an empty parameter pack expansion, we should erase the + // comma we just printed. + if (AfterComma == S.getCurrentPosition()) { + S.setCurrentPosition(BeforeComma); + continue; + } + + FirstElement = false; + } + } +}; + +struct NodeArrayNode : Node { + NodeArray Array; + NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} + void printLeft(OutputStream &S) const override { + Array.printWithComma(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 *Ty; + StringView Ext; + +public: + VendorExtQualType(Node *Ty_, StringView Ext_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + + void printLeft(OutputStream &S) const override { + Ty->print(S); + S += " "; + S += Ext; + } +}; + +enum FunctionRefQual : unsigned char { + FrefQualNone, + FrefQualLValue, + FrefQualRValue, +}; + +enum Qualifiers { + QualNone = 0, + QualConst = 0x1, + QualVolatile = 0x2, + QualRestrict = 0x4, +}; + +void addQualifiers(Qualifiers &Q1, Qualifiers Q2) { + Q1 = static_cast(Q1 | Q2); +} + +class QualType : public Node { +protected: + const Qualifiers Quals; + const Node *Child; + + void printQuals(OutputStream &S) const { + if (Quals & QualConst) + S += " const"; + if (Quals & QualVolatile) + S += " volatile"; + if (Quals & QualRestrict) + S += " restrict"; + } + +public: + QualType(Node *Child_, Qualifiers Quals_) + : Node(KQualType, Child_->RHSComponentCache, + Child_->ArrayCache, Child_->FunctionCache), + Quals(Quals_), Child(Child_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + return Child->hasRHSComponent(S); + } + bool hasArraySlow(OutputStream &S) const override { + return Child->hasArray(S); + } + bool hasFunctionSlow(OutputStream &S) const override { + return Child->hasFunction(S); + } + + 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; + } +}; + +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 ElaboratedTypeSpefType : public Node { + StringView Kind; + Node *Child; +public: + ElaboratedTypeSpefType(StringView Kind_, Node *Child_) + : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} + + void printLeft(OutputStream &S) const override { + S += Kind; + S += ' '; + Child->print(S); + } +}; + +struct AbiTagAttr : Node { + Node *Base; + StringView Tag; + + AbiTagAttr(Node* Base_, StringView Tag_) + : Node(KAbiTagAttr, Base_->RHSComponentCache, + Base_->ArrayCache, Base_->FunctionCache), + Base(Base_), Tag(Tag_) {} + + void printLeft(OutputStream &S) const override { + Base->printLeft(S); + S += "[abi:"; + S += Tag; + S += "]"; + } +}; + +class EnableIfAttr : public Node { + NodeArray Conditions; +public: + EnableIfAttr(NodeArray Conditions_) + : Node(KEnableIfAttr), Conditions(Conditions_) {} + + void printLeft(OutputStream &S) const override { + S += " [enable_if:"; + Conditions.printWithComma(S); + S += ']'; + } +}; + +class ObjCProtoName : public Node { + Node *Ty; + StringView Protocol; + + friend class PointerType; + +public: + ObjCProtoName(Node *Ty_, StringView Protocol_) + : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} + + bool isObjCObject() const { + return Ty->getKind() == KNameType && + static_cast(Ty)->getName() == "objc_object"; + } + + void printLeft(OutputStream &S) const override { + Ty->print(S); + S += "<"; + S += Protocol; + S += ">"; + } +}; + +class PointerType final : public Node { + const Node *Pointee; + +public: + PointerType(Node *Pointee_) + : Node(KPointerType, Pointee_->RHSComponentCache), + Pointee(Pointee_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + return Pointee->hasRHSComponent(S); + } + + void printLeft(OutputStream &s) const override { + // We rewrite objc_object* into id. + if (Pointee->getKind() != KObjCProtoName || + !static_cast(Pointee)->isObjCObject()) { + Pointee->printLeft(s); + if (Pointee->hasArray(s)) + s += " "; + if (Pointee->hasArray(s) || Pointee->hasFunction(s)) + s += "("; + s += "*"; + } else { + const auto *objcProto = static_cast(Pointee); + s += "id<"; + s += objcProto->Protocol; + s += ">"; + } + } + + void printRight(OutputStream &s) const override { + if (Pointee->getKind() != KObjCProtoName || + !static_cast(Pointee)->isObjCObject()) { + if (Pointee->hasArray(s) || Pointee->hasFunction(s)) + s += ")"; + Pointee->printRight(s); + } + } +}; + +enum class ReferenceKind { + LValue, + RValue, +}; + +// Represents either a LValue or an RValue reference type. +class ReferenceType : public Node { + const Node *Pointee; + ReferenceKind RK; + + mutable bool Printing = false; + + // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The + // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any + // other combination collapses to a lvalue ref. + std::pair collapse(OutputStream &S) const { + auto SoFar = std::make_pair(RK, Pointee); + for (;;) { + const Node *SN = SoFar.second->getSyntaxNode(S); + if (SN->getKind() != KReferenceType) + break; + auto *RT = static_cast(SN); + SoFar.second = RT->Pointee; + SoFar.first = std::min(SoFar.first, RT->RK); + } + return SoFar; + } + +public: + ReferenceType(Node *Pointee_, ReferenceKind RK_) + : Node(KReferenceType, Pointee_->RHSComponentCache), + Pointee(Pointee_), RK(RK_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + return Pointee->hasRHSComponent(S); + } + + void printLeft(OutputStream &s) const override { + if (Printing) + return; + SwapAndRestore SavePrinting(Printing, true); + std::pair Collapsed = collapse(s); + Collapsed.second->printLeft(s); + if (Collapsed.second->hasArray(s)) + s += " "; + if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) + s += "("; + + s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + } + void printRight(OutputStream &s) const override { + if (Printing) + return; + SwapAndRestore SavePrinting(Printing, true); + std::pair Collapsed = collapse(s); + if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) + s += ")"; + Collapsed.second->printRight(s); + } +}; + +class PointerToMemberType final : public Node { + const Node *ClassType; + const Node *MemberType; + +public: + PointerToMemberType(Node *ClassType_, Node *MemberType_) + : Node(KPointerToMemberType, MemberType_->RHSComponentCache), + ClassType(ClassType_), MemberType(MemberType_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + return MemberType->hasRHSComponent(S); + } + + void printLeft(OutputStream &s) const override { + MemberType->printLeft(s); + if (MemberType->hasArray(s) || MemberType->hasFunction(s)) + s += "("; + else + s += " "; + ClassType->print(s); + s += "::*"; + } + + void printRight(OutputStream &s) const override { + if (MemberType->hasArray(s) || MemberType->hasFunction(s)) + s += ")"; + MemberType->printRight(s); + } +}; + +class NodeOrString { + const void *First; + const void *Second; + +public: + /* implicit */ NodeOrString(StringView Str) { + const char *FirstChar = Str.begin(); + const char *SecondChar = Str.end(); + if (SecondChar == nullptr) { + assert(FirstChar == SecondChar); + ++FirstChar, ++SecondChar; + } + First = static_cast(FirstChar); + Second = static_cast(SecondChar); + } + + /* implicit */ NodeOrString(Node *N) + : First(static_cast(N)), Second(nullptr) {} + NodeOrString() : First(nullptr), Second(nullptr) {} + + bool isString() const { return Second && First; } + bool isNode() const { return First && !Second; } + bool isEmpty() const { return !First && !Second; } + + StringView asString() const { + assert(isString()); + return StringView(static_cast(First), + static_cast(Second)); + } + + const Node *asNode() const { + assert(isNode()); + return static_cast(First); + } +}; + +class ArrayType final : public Node { + Node *Base; + NodeOrString Dimension; + +public: + ArrayType(Node *Base_, NodeOrString Dimension_) + : Node(KArrayType, + /*RHSComponentCache=*/Cache::Yes, + /*ArrayCache=*/Cache::Yes), + Base(Base_), Dimension(Dimension_) {} + + // Incomplete array type. + ArrayType(Node *Base_) + : Node(KArrayType, + /*RHSComponentCache=*/Cache::Yes, + /*ArrayCache=*/Cache::Yes), + Base(Base_) {} + + bool hasRHSComponentSlow(OutputStream &) const override { return true; } + bool hasArraySlow(OutputStream &) const override { return true; } + + 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; + Qualifiers CVQuals; + FunctionRefQual RefQual; + Node *ExceptionSpec; + +public: + FunctionType(Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, + FunctionRefQual RefQual_, Node *ExceptionSpec_) + : Node(KFunctionType, + /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, + /*FunctionCache=*/Cache::Yes), + Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), + ExceptionSpec(ExceptionSpec_) {} + + bool hasRHSComponentSlow(OutputStream &) const override { return true; } + bool hasFunctionSlow(OutputStream &) const override { return true; } + + // Handle C++'s ... quirky decl grammar 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.printWithComma(S); + S += ")"; + Ret->printRight(S); + + if (CVQuals & QualConst) + S += " const"; + if (CVQuals & QualVolatile) + S += " volatile"; + if (CVQuals & QualRestrict) + S += " restrict"; + + if (RefQual == FrefQualLValue) + S += " &"; + else if (RefQual == FrefQualRValue) + S += " &&"; + + if (ExceptionSpec != nullptr) { + S += ' '; + ExceptionSpec->print(S); + } + } +}; + +class NoexceptSpec : public Node { + Node *E; +public: + NoexceptSpec(Node *E_) : Node(KNoexceptSpec), E(E_) {} + + void printLeft(OutputStream &S) const override { + S += "noexcept("; + E->print(S); + S += ")"; + } +}; + +class DynamicExceptionSpec : public Node { + NodeArray Types; +public: + DynamicExceptionSpec(NodeArray Types_) + : Node(KDynamicExceptionSpec), Types(Types_) {} + + void printLeft(OutputStream &S) const override { + S += "throw("; + Types.printWithComma(S); + S += ')'; + } +}; + +class FunctionEncoding final : public Node { + Node *Ret; + Node *Name; + NodeArray Params; + Node *Attrs; + Qualifiers CVQuals; + FunctionRefQual RefQual; + +public: + FunctionEncoding(Node *Ret_, Node *Name_, NodeArray Params_, + Node *Attrs_, Qualifiers CVQuals_, FunctionRefQual RefQual_) + : Node(KFunctionEncoding, + /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, + /*FunctionCache=*/Cache::Yes), + Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), + CVQuals(CVQuals_), RefQual(RefQual_) {} + + Qualifiers getCVQuals() const { return CVQuals; } + FunctionRefQual getRefQual() const { return RefQual; } + NodeArray getParams() const { return Params; } + Node *getReturnType() const { return Ret; } + + bool hasRHSComponentSlow(OutputStream &) const override { return true; } + bool hasFunctionSlow(OutputStream &) const override { return true; } + + Node *getName() { return const_cast(Name); } + + void printLeft(OutputStream &S) const override { + if (Ret) { + Ret->printLeft(S); + if (!Ret->hasRHSComponent(S)) + S += " "; + } + Name->print(S); + } + + void printRight(OutputStream &S) const override { + S += "("; + Params.printWithComma(S); + S += ")"; + if (Ret) + Ret->printRight(S); + + if (CVQuals & QualConst) + S += " const"; + if (CVQuals & QualVolatile) + S += " volatile"; + if (CVQuals & QualRestrict) + S += " restrict"; + + if (RefQual == FrefQualLValue) + S += " &"; + else if (RefQual == FrefQualRValue) + S += " &&"; + + if (Attrs != nullptr) + Attrs->print(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); + } +}; + +struct NestedName : Node { + Node *Qual; + Node *Name; + + NestedName(Node *Qual_, Node *Name_) + : Node(KNestedName), Qual(Qual_), Name(Name_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Qual->print(S); + S += "::"; + Name->print(S); + } +}; + +struct LocalName : Node { + Node *Encoding; + Node *Entity; + + LocalName(Node *Encoding_, Node *Entity_) + : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} + + void printLeft(OutputStream &S) const override { + Encoding->print(S); + S += "::"; + Entity->print(S); + } +}; + +class QualifiedName final : public Node { + // qualifier::name + const Node *Qualifier; + const Node *Name; + +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 { + Qualifier->print(S); + S += "::"; + Name->print(S); + } +}; + +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 += "]"; + } + } +}; + +/// An unexpanded parameter pack (either in the expression or type context). If +/// this AST is correct, this node will have a ParameterPackExpansion node above +/// it. +/// +/// This node is created when some are found that apply to an +/// , and is stored in the TemplateParams table. In order for this to +/// appear in the final AST, it has to referenced via a (ie, +/// T_). +class ParameterPack final : public Node { + NodeArray Data; + + // Setup OutputStream for a pack expansion unless we're already expanding one. + void initializePackExpansion(OutputStream &S) const { + if (S.CurrentPackMax == std::numeric_limits::max()) { + S.CurrentPackMax = static_cast(Data.size()); + S.CurrentPackIndex = 0; + } + } + +public: + ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { + ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; + if (std::all_of(Data.begin(), Data.end(), [](Node* P) { + return P->ArrayCache == Cache::No; + })) + ArrayCache = Cache::No; + if (std::all_of(Data.begin(), Data.end(), [](Node* P) { + return P->FunctionCache == Cache::No; + })) + FunctionCache = Cache::No; + if (std::all_of(Data.begin(), Data.end(), [](Node* P) { + return P->RHSComponentCache == Cache::No; + })) + RHSComponentCache = Cache::No; + } + + bool hasRHSComponentSlow(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + } + bool hasArraySlow(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(S); + } + bool hasFunctionSlow(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(S); + } + const Node *getSyntaxNode(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + } + + void printLeft(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + if (Idx < Data.size()) + Data[Idx]->printLeft(S); + } + void printRight(OutputStream &S) const override { + initializePackExpansion(S); + size_t Idx = S.CurrentPackIndex; + if (Idx < Data.size()) + Data[Idx]->printRight(S); + } +}; + +/// A variadic template argument. This node represents an occurrence of +/// JE in some . It isn't itself unexpanded, unless +/// one of it's Elements is. The parser inserts a ParameterPack into the +/// TemplateParams table if the this pack belongs to apply to an +/// . +class TemplateArgumentPack final : public Node { + NodeArray Elements; +public: + TemplateArgumentPack(NodeArray Elements_) + : Node(KTemplateArgumentPack), Elements(Elements_) {} + + NodeArray getElements() const { return Elements; } + + void printLeft(OutputStream &S) const override { + Elements.printWithComma(S); + } +}; + +/// A pack expansion. Below this node, there are some unexpanded ParameterPacks +/// which each have Child->ParameterPackSize elements. +class ParameterPackExpansion final : public Node { + const Node *Child; + +public: + ParameterPackExpansion(Node* Child_) + : Node(KParameterPackExpansion), Child(Child_) {} + + const Node *getChild() const { return Child; } + + void printLeft(OutputStream &S) const override { + constexpr unsigned Max = std::numeric_limits::max(); + SwapAndRestore SavePackIdx(S.CurrentPackIndex, Max); + SwapAndRestore SavePackMax(S.CurrentPackMax, Max); + size_t StreamPos = S.getCurrentPosition(); + + // Print the first element in the pack. If Child contains a ParameterPack, + // it will set up S.CurrentPackMax and print the first element. + Child->print(S); + + // No ParameterPack was found in Child. This can occur if we've found a pack + // expansion on a . + if (S.CurrentPackMax == Max) { + S += "..."; + return; + } + + // We found a ParameterPack, but it has no elements. Erase whatever we may + // of printed. + if (S.CurrentPackMax == 0) { + S.setCurrentPosition(StreamPos); + return; + } + + // Else, iterate through the rest of the elements in the pack. + for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { + S += ", "; + S.CurrentPackIndex = I; + Child->print(S); + } + } +}; + +class TemplateArgs final : public Node { + NodeArray Params; + +public: + TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} + + NodeArray getParams() { return Params; } + + void printLeft(OutputStream &S) const override { + S += "<"; + Params.printWithComma(S); + if (S.back() == '>') + S += " "; + S += ">"; + } +}; + +struct ForwardTemplateReference : Node { + size_t Index; + Node *Ref = nullptr; + + // If we're currently printing this node. It is possible (though invalid) for + // a forward template reference to refer to itself via a substitution. This + // creates a cyclic AST, which will stack overflow printing. To fix this, bail + // out if more than one print* function is active. + mutable bool Printing = false; + + ForwardTemplateReference(size_t Index_) + : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, + Cache::Unknown), + Index(Index_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + if (Printing) + return false; + SwapAndRestore SavePrinting(Printing, true); + return Ref->hasRHSComponent(S); + } + bool hasArraySlow(OutputStream &S) const override { + if (Printing) + return false; + SwapAndRestore SavePrinting(Printing, true); + return Ref->hasArray(S); + } + bool hasFunctionSlow(OutputStream &S) const override { + if (Printing) + return false; + SwapAndRestore SavePrinting(Printing, true); + return Ref->hasFunction(S); + } + const Node *getSyntaxNode(OutputStream &S) const override { + if (Printing) + return this; + SwapAndRestore SavePrinting(Printing, true); + return Ref->getSyntaxNode(S); + } + + void printLeft(OutputStream &S) const override { + if (Printing) + return; + SwapAndRestore SavePrinting(Printing, true); + Ref->printLeft(S); + } + void printRight(OutputStream &S) const override { + if (Printing) + return; + SwapAndRestore SavePrinting(Printing, true); + Ref->printRight(S); + } +}; + +struct NameWithTemplateArgs : Node { + // name + Node *Name; + Node *TemplateArgs; + + 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); + } +}; + +struct StdQualifiedName : Node { + Node *Child; + + StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} + + StringView getBaseName() const override { return Child->getBaseName(); } + + void printLeft(OutputStream &S) const override { + S += "std::"; + Child->print(S); + } +}; + +enum class SpecialSubKind { + allocator, + basic_string, + string, + istream, + ostream, + iostream, +}; + +class ExpandedSpecialSubstitution final : public Node { + SpecialSubKind SSK; + +public: + ExpandedSpecialSubstitution(SpecialSubKind SSK_) + : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("basic_string"); + case SpecialSubKind::istream: + return StringView("basic_istream"); + case SpecialSubKind::ostream: + return StringView("basic_ostream"); + case SpecialSubKind::iostream: + return StringView("basic_iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::basic_string, " + "std::allocator >"; + break; + case SpecialSubKind::basic_string: + case SpecialSubKind::string: + S += "std::basic_string, " + "std::allocator >"; + break; + case SpecialSubKind::istream: + S += "std::basic_istream >"; + break; + case SpecialSubKind::ostream: + S += "std::basic_ostream >"; + break; + case SpecialSubKind::iostream: + S += "std::basic_iostream >"; + break; + } + } +}; + +class SpecialSubstitution final : public Node { +public: + SpecialSubKind SSK; + + SpecialSubstitution(SpecialSubKind SSK_) + : Node(KSpecialSubstitution), SSK(SSK_) {} + + StringView getBaseName() const override { + switch (SSK) { + case SpecialSubKind::allocator: + return StringView("allocator"); + case SpecialSubKind::basic_string: + return StringView("basic_string"); + case SpecialSubKind::string: + return StringView("string"); + case SpecialSubKind::istream: + return StringView("istream"); + case SpecialSubKind::ostream: + return StringView("ostream"); + case SpecialSubKind::iostream: + return StringView("iostream"); + } + _LIBCPP_UNREACHABLE(); + } + + void printLeft(OutputStream &S) const override { + switch (SSK) { + case SpecialSubKind::allocator: + S += "std::allocator"; + break; + case SpecialSubKind::basic_string: + S += "std::basic_string"; + break; + case SpecialSubKind::string: + S += "std::string"; + break; + case SpecialSubKind::istream: + S += "std::istream"; + break; + case SpecialSubKind::ostream: + S += "std::ostream"; + break; + case SpecialSubKind::iostream: + S += "std::iostream"; + break; + } + } +}; + +class CtorDtorName final : public Node { + const Node *Basename; + const bool IsDtor; + +public: + CtorDtorName(Node *Basename_, bool IsDtor_) + : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_) {} + + void printLeft(OutputStream &S) const override { + if (IsDtor) + S += "~"; + S += Basename->getBaseName(); + } +}; + +class DtorName : public Node { + const Node *Base; + +public: + DtorName(Node *Base_) : Node(KDtorName), Base(Base_) {} + + void printLeft(OutputStream &S) const override { + S += "~"; + Base->printLeft(S); + } +}; + +class UnnamedTypeName : public Node { + const StringView Count; + +public: + UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "'unnamed"; + S += Count; + S += "\'"; + } +}; + +class ClosureTypeName : public Node { + NodeArray Params; + StringView Count; + +public: + ClosureTypeName(NodeArray Params_, StringView Count_) + : Node(KClosureTypeName), Params(Params_), Count(Count_) {} + + void printLeft(OutputStream &S) const override { + S += "\'lambda"; + S += Count; + S += "\'("; + Params.printWithComma(S); + S += ")"; + } +}; + +class StructuredBindingName : public Node { + NodeArray Bindings; +public: + StructuredBindingName(NodeArray Bindings_) + : Node(KStructuredBindingName), Bindings(Bindings_) {} + + void printLeft(OutputStream &S) const override { + S += '['; + Bindings.printWithComma(S); + S += ']'; + } +}; + +// -- Expression Nodes -- + +struct Expr : public Node { + Expr(Kind K = KExpr) : Node(K) {} +}; + +class BinaryExpr : public Expr { + const Node *LHS; + const StringView InfixOperator; + const Node *RHS; + +public: + BinaryExpr(Node *LHS_, StringView InfixOperator_, Node *RHS_) + : LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + // might be a template argument expression, then we need to disambiguate + // with parens. + if (InfixOperator == ">") + S += "("; + + S += "("; + LHS->print(S); + S += ") "; + S += InfixOperator; + S += " ("; + RHS->print(S); + S += ")"; + + if (InfixOperator == ">") + S += ")"; + } +}; + +class ArraySubscriptExpr : public Expr { + const Node *Op1; + const Node *Op2; + +public: + ArraySubscriptExpr(Node *Op1_, Node *Op2_) : Op1(Op1_), Op2(Op2_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Op1->print(S); + S += ")["; + Op2->print(S); + S += "]"; + } +}; + +class PostfixExpr : public Expr { + const Node *Child; + const StringView Operand; + +public: + PostfixExpr(Node *Child_, StringView Operand_) + : Child(Child_), Operand(Operand_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Child->print(S); + S += ")"; + S += Operand; + } +}; + +class ConditionalExpr : public Expr { + const Node *Cond; + const Node *Then; + const Node *Else; + +public: + ConditionalExpr(Node *Cond_, Node *Then_, Node *Else_) + : Cond(Cond_), Then(Then_), Else(Else_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Cond->print(S); + S += ") ? ("; + Then->print(S); + S += ") : ("; + Else->print(S); + S += ")"; + } +}; + +class MemberExpr : public Expr { + const Node *LHS; + const StringView Kind; + const Node *RHS; + +public: + MemberExpr(Node *LHS_, StringView Kind_, Node *RHS_) + : LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + void printLeft(OutputStream &S) const override { + LHS->print(S); + S += Kind; + RHS->print(S); + } +}; + +class EnclosingExpr : public Expr { + const StringView Prefix; + const Node *Infix; + const StringView Postfix; + +public: + EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) + : Prefix(Prefix_), Infix(Infix_), Postfix(Postfix_) {} + + void printLeft(OutputStream &S) const override { + S += Prefix; + Infix->print(S); + S += Postfix; + } +}; + +class CastExpr : public Expr { + // cast_kind(from) + const StringView CastKind; + const Node *To; + const Node *From; + +public: + CastExpr(StringView CastKind_, Node *To_, Node *From_) + : CastKind(CastKind_), To(To_), From(From_) {} + + void printLeft(OutputStream &S) const override { + S += CastKind; + S += "<"; + To->printLeft(S); + S += ">("; + From->printLeft(S); + S += ")"; + } +}; + +class SizeofParamPackExpr : public Expr { + Node *Pack; + +public: + SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {} + + void printLeft(OutputStream &S) const override { + S += "sizeof...("; + ParameterPackExpansion PPE(Pack); + PPE.printLeft(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.printWithComma(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 += "[]"; + S += ' '; + if (!ExprList.empty()) { + S += "("; + ExprList.printWithComma(S); + S += ")"; + } + Type->print(S); + if (!InitList.empty()) { + S += "("; + InitList.printWithComma(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 ConversionExpr : public Expr { + const Node *Type; + NodeArray Expressions; + +public: + ConversionExpr(const Node *Type_, NodeArray Expressions_) + : Type(Type_), Expressions(Expressions_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Type->print(S); + S += ")("; + Expressions.printWithComma(S); + S += ")"; + } +}; + +class InitListExpr : public Expr { + Node *Ty; + NodeArray Inits; +public: + InitListExpr(Node *Ty_, NodeArray Inits_) : Ty(Ty_), Inits(Inits_) {} + + void printLeft(OutputStream &S) const override { + if (Ty) + Ty->print(S); + S += '{'; + Inits.printWithComma(S); + S += '}'; + } +}; + +class BracedExpr : public Expr { + Node *Elem; + Node *Init; + bool IsArray; +public: + BracedExpr(Node *Elem_, Node *Init_, bool IsArray_) + : Expr(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} + + void printLeft(OutputStream &S) const override { + if (IsArray) { + S += '['; + Elem->print(S); + S += ']'; + } else { + S += '.'; + Elem->print(S); + } + if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) + S += " = "; + Init->print(S); + } +}; + +class BracedRangeExpr : public Expr { + Node *First; + Node *Last; + Node *Init; +public: + BracedRangeExpr(Node *First_, Node *Last_, Node *Init_) + : Expr(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} + + void printLeft(OutputStream &S) const override { + S += '['; + First->print(S); + S += " ... "; + Last->print(S); + S += ']'; + if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) + S += " = "; + Init->print(S); + } +}; + +struct FoldExpr : Expr { + Node *Pack, *Init; + StringView OperatorName; + bool IsLeftFold; + + FoldExpr(bool IsLeftFold_, StringView OperatorName_, Node *Pack_, Node *Init_) + : Pack(Pack_), Init(Init_), OperatorName(OperatorName_), + IsLeftFold(IsLeftFold_) {} + + void printLeft(OutputStream &S) const override { + auto PrintPack = [&] { + S += '('; + ParameterPackExpansion(Pack).print(S); + S += ')'; + }; + + S += '('; + + if (IsLeftFold) { + // init op ... op pack + if (Init != nullptr) { + Init->print(S); + S += ' '; + S += OperatorName; + S += ' '; + } + // ... op pack + S += "... "; + S += OperatorName; + S += ' '; + PrintPack(); + } else { // !IsLeftFold + // pack op ... + PrintPack(); + S += ' '; + S += OperatorName; + S += " ..."; + // pack op ... op init + if (Init != nullptr) { + S += ' '; + S += OperatorName; + S += ' '; + Init->print(S); + } + } + S += ')'; + } +}; + +class ThrowExpr : public Expr { + const Node *Op; + +public: + ThrowExpr(Node *Op_) : Op(Op_) {} + + void printLeft(OutputStream &S) const override { + S += "throw "; + Op->print(S); + } +}; + +class BoolExpr : public Expr { + bool Value; + +public: + BoolExpr(bool Value_) : Value(Value_) {} + + void printLeft(OutputStream &S) const override { + S += Value ? StringView("true") : StringView("false"); + } +}; + +class IntegerCastExpr : public Expr { + // ty(integer) + Node *Ty; + StringView Integer; + +public: + IntegerCastExpr(Node *Ty_, StringView Integer_) + : Ty(Ty_), Integer(Integer_) {} + + void printLeft(OutputStream &S) const override { + S += "("; + Ty->print(S); + S += ")"; + S += Integer; + } +}; + +class IntegerExpr : public Expr { + StringView Type; + StringView Value; + +public: + IntegerExpr(StringView Type_, StringView Value_) : Type(Type_), Value(Value_) {} + + void printLeft(OutputStream &S) const override { + if (Type.size() > 3) { + S += "("; + S += Type; + S += ")"; + } + + if (Value[0] == 'n') { + S += "-"; + S += Value.dropFront(1); + } else + S += Value; + + if (Type.size() <= 3) + S += Type; + } +}; + +template struct FloatData; + +template class FloatExpr : public Expr { + const StringView Contents; + +public: + FloatExpr(StringView Contents_) : Contents(Contents_) {} + + void printLeft(OutputStream &s) const override { + const char *first = Contents.begin(); + const char *last = Contents.end() + 1; + + const size_t N = FloatData::mangled_size; + if (static_cast(last - first) > N) { + last = first + N; + union { + Float value; + char buf[sizeof(Float)]; + }; + const char *t = first; + char *e = buf; + for (; t != last; ++t, ++e) { + unsigned d1 = isdigit(*t) ? static_cast(*t - '0') + : static_cast(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast(*t - '0') + : static_cast(*t - 'a' + 10); + *e = static_cast((d1 << 4) + d0); + } +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[FloatData::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), FloatData::spec, value); + s += StringView(num, num + n); + } + } +}; + +class BumpPointerAllocator { + struct BlockMeta { + BlockMeta* Next; + size_t Current; + }; + + static constexpr size_t AllocSize = 4096; + static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); + + alignas(long double) char InitialBuffer[AllocSize]; + BlockMeta* BlockList = nullptr; + + void grow() { + char* NewMeta = static_cast(std::malloc(AllocSize)); + if (NewMeta == nullptr) + std::terminate(); + BlockList = new (NewMeta) BlockMeta{BlockList, 0}; + } + + void* allocateMassive(size_t NBytes) { + NBytes += sizeof(BlockMeta); + BlockMeta* NewMeta = reinterpret_cast(std::malloc(NBytes)); + if (NewMeta == nullptr) + std::terminate(); + BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; + return static_cast(NewMeta + 1); + } + +public: + BumpPointerAllocator() + : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} + + void* allocate(size_t N) { + N = (N + 15u) & ~15u; + if (N + BlockList->Current >= UsableAllocSize) { + if (N > UsableAllocSize) + return allocateMassive(N); + grow(); + } + BlockList->Current += N; + return static_cast(reinterpret_cast(BlockList + 1) + + BlockList->Current - N); + } + + void reset() { + while (BlockList) { + BlockMeta* Tmp = BlockList; + BlockList = BlockList->Next; + if (reinterpret_cast(Tmp) != InitialBuffer) + std::free(Tmp); + } + BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; + } + + ~BumpPointerAllocator() { reset(); } +}; + +template +class PODSmallVector { + static_assert(std::is_pod::value, + "T is required to be a plain old data type"); + + T* First; + T* Last; + T* Cap; + T Inline[N]; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto* Tmp = static_cast(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector&) = delete; + PODSmallVector& operator=(const PODSmallVector&) = delete; + + PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector& operator=(PODSmallVector&& Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + void push_back(const T& Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T* begin() { return First; } + T* end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast(Last - First); } + T& back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T& operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + +struct Db { + const char *First; + const char *Last; + + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser collapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 44nd entry (base-36) in this + // table. + PODSmallVector Subs; + + // 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. + PODSmallVector TemplateParams; + + // Set of unresolved forward references. These can occur in a + // conversion operator's type, and are resolved in the enclosing . + PODSmallVector ForwardTemplateRefs; + + bool TryToParseTemplateArgs = true; + bool PermitForwardTemplateReferences = false; + bool ParsingLambdaParams = false; + + BumpPointerAllocator ASTAllocator; + + Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + + void reset(const char *First_, const char *Last_) { + First = First_; + Last = Last_; + Names.clear(); + Subs.clear(); + TemplateParams.clear(); + ParsingLambdaParams = false; + TryToParseTemplateArgs = true; + PermitForwardTemplateReferences = false; + ASTAllocator.reset(); + } + + template T *make(Args &&... args) { + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward(args)...); + } + + template NodeArray makeNodeArray(It begin, It end) { + size_t sz = static_cast(end - begin); + void *mem = ASTAllocator.allocate(sizeof(Node *) * sz); + Node **data = new (mem) Node *[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); + } + + NodeArray popTrailingNodeArray(size_t FromPosition) { + assert(FromPosition <= Names.size()); + NodeArray res = + makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } + + bool consumeIf(StringView S) { + if (StringView(First, Last).startsWith(S)) { + First += S.size(); + return true; + } + return false; + } + + bool consumeIf(char C) { + if (First != Last && *First == C) { + ++First; + return true; + } + return false; + } + + char consume() { return First != Last ? *First++ : '\0'; } + + char look(unsigned Lookahead = 0) { + if (static_cast(Last - First) <= Lookahead) + return '\0'; + return First[Lookahead]; + } + + size_t numLeft() const { return static_cast(Last - First); } + + StringView parseNumber(bool AllowNegative = false); + Qualifiers parseCVQualifiers(); + bool parsePositiveInteger(size_t *Out); + StringView parseBareSourceName(); + + bool parseSeqId(size_t *Out); + Node *parseSubstitution(); + Node *parseTemplateParam(); + Node *parseTemplateArgs(bool TagTemplates = false); + Node *parseTemplateArg(); + + /// Parse the production. + Node *parseExpr(); + Node *parsePrefixExpr(StringView Kind); + Node *parseBinaryExpr(StringView Kind); + Node *parseIntegerLiteral(StringView Lit); + Node *parseExprPrimary(); + template Node *parseFloatingLiteral(); + Node *parseFunctionParam(); + Node *parseNewExpr(); + Node *parseConversionExpr(); + Node *parseBracedExpr(); + Node *parseFoldExpr(); + + /// Parse the production. + Node *parseType(); + Node *parseFunctionType(); + Node *parseVectorType(); + Node *parseDecltype(); + Node *parseArrayType(); + Node *parsePointerToMemberType(); + Node *parseClassEnumType(); + Node *parseQualifiedType(); + + Node *parseEncoding(); + bool parseCallOffset(); + Node *parseSpecialName(); + + /// Holds some extra information about a that is being parsed. This + /// information is only pertinent if the refers to an . + struct NameState { + bool CtorDtorConversion = false; + bool EndsWithTemplateArgs = false; + Qualifiers CVQualifiers = QualNone; + FunctionRefQual ReferenceQualifier = FrefQualNone; + size_t ForwardTemplateRefsBegin; + + NameState(Db *Enclosing) + : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} + }; + + bool resolveForwardTemplateRefs(NameState &State) { + size_t I = State.ForwardTemplateRefsBegin; + size_t E = ForwardTemplateRefs.size(); + for (; I < E; ++I) { + size_t Idx = ForwardTemplateRefs[I]->Index; + if (Idx >= TemplateParams.size()) + return true; + ForwardTemplateRefs[I]->Ref = TemplateParams[Idx]; + } + ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); + return false; + } + + /// Parse the production> + Node *parseName(NameState *State = nullptr); + Node *parseLocalName(NameState *State); + Node *parseOperatorName(NameState *State); + Node *parseUnqualifiedName(NameState *State); + Node *parseUnnamedTypeName(NameState *State); + Node *parseSourceName(NameState *State); + Node *parseUnscopedName(NameState *State); + Node *parseNestedName(NameState *State); + Node *parseCtorDtorName(Node *&SoFar, NameState *State); + + Node *parseAbiTags(Node *N); + + /// Parse the production. + Node *parseUnresolvedName(); + Node *parseSimpleId(); + Node *parseBaseUnresolvedName(); + Node *parseUnresolvedType(); + Node *parseDestructorName(); + + /// Top-level entry point into the parser. + Node *parse(); +}; + +const char* parse_discriminator(const char* first, const char* last); + +// ::= // N +// ::= # See Scope Encoding below // Z +// ::= +// ::= +// +// ::= +// ::= +Node *Db::parseName(NameState *State) { + consumeIf('L'); // extension + + if (look() == 'N') + return parseNestedName(State); + if (look() == 'Z') + return parseLocalName(State); + + // ::= + if (look() == 'S' && look(1) != 't') { + Node *S = parseSubstitution(); + if (S == nullptr) + return nullptr; + if (look() != 'I') + return nullptr; + Node *TA = parseTemplateArgs(State != nullptr); + if (TA == nullptr) + return nullptr; + if (State) State->EndsWithTemplateArgs = true; + return make(S, TA); + } + + Node *N = parseUnscopedName(State); + if (N == nullptr) + return nullptr; + // ::= + if (look() == 'I') { + Subs.push_back(N); + Node *TA = parseTemplateArgs(State != nullptr); + if (TA == nullptr) + return nullptr; + if (State) State->EndsWithTemplateArgs = true; + return make(N, TA); + } + // ::= + return N; +} + +// := Z E [] +// := Z E s [] +// := Z Ed [ ] _ +Node *Db::parseLocalName(NameState *State) { + if (!consumeIf('Z')) + return nullptr; + Node *Encoding = parseEncoding(); + if (Encoding == nullptr || !consumeIf('E')) + return nullptr; + + if (consumeIf('s')) { + First = parse_discriminator(First, Last); + return make(Encoding, make("string literal")); + } + + if (consumeIf('d')) { + parseNumber(true); + if (!consumeIf('_')) + return nullptr; + Node *N = parseName(State); + if (N == nullptr) + return nullptr; + return make(Encoding, N); + } + + Node *Entity = parseName(State); + if (Entity == nullptr) + return nullptr; + First = parse_discriminator(First, Last); + return make(Encoding, Entity); +} + +// ::= +// ::= St # ::std:: +// extension ::= StL +Node *Db::parseUnscopedName(NameState *State) { + if (consumeIf("StL") || consumeIf("St")) { + Node *R = parseUnqualifiedName(State); + if (R == nullptr) + return nullptr; + return make(R); + } + return parseUnqualifiedName(State); +} + +// ::= [abi-tags] +// ::= +// ::= +// ::= +// ::= DC + E # structured binding declaration +Node *Db::parseUnqualifiedName(NameState *State) { + // s are special-cased in parseNestedName(). + Node *Result; + if (look() == 'U') + Result = parseUnnamedTypeName(State); + else if (look() >= '1' && look() <= '9') + Result = parseSourceName(State); + else if (consumeIf("DC")) { + size_t BindingsBegin = Names.size(); + do { + Node *Binding = parseSourceName(State); + if (Binding == nullptr) + return nullptr; + Names.push_back(Binding); + } while (!consumeIf('E')); + Result = make(popTrailingNodeArray(BindingsBegin)); + } else + Result = parseOperatorName(State); + if (Result != nullptr) + Result = parseAbiTags(Result); + return Result; +} + +// ::= Ut [] _ +// ::= +// +// ::= Ul E [ ] _ +// +// ::= + # Parameter types or "v" if the lambda has no parameters +Node *Db::parseUnnamedTypeName(NameState *) { + if (consumeIf("Ut")) { + StringView Count = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Count); + } + if (consumeIf("Ul")) { + NodeArray Params; + SwapAndRestore SwapParams(ParsingLambdaParams, true); + if (!consumeIf("vE")) { + size_t ParamsBegin = Names.size(); + do { + Node *P = parseType(); + if (P == nullptr) + return nullptr; + Names.push_back(P); + } while (!consumeIf('E')); + Params = popTrailingNodeArray(ParamsBegin); + } + StringView Count = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Params, Count); + } + return nullptr; +} + +// ::= +Node *Db::parseSourceName(NameState *) { + size_t Length = 0; + if (parsePositiveInteger(&Length)) + return nullptr; + if (numLeft() < Length || Length == 0) + return nullptr; + StringView Name(First, First + Length); + First += Length; + if (Name.startsWith("_GLOBAL__N")) + return make("(anonymous namespace)"); + return make(Name); +} + +// ::= aa # && +// ::= ad # & (unary) +// ::= an # & +// ::= aN # &= +// ::= aS # = +// ::= cl # () +// ::= cm # , +// ::= co # ~ +// ::= cv # (cast) +// ::= da # delete[] +// ::= de # * (unary) +// ::= dl # delete +// ::= dv # / +// ::= dV # /= +// ::= eo # ^ +// ::= eO # ^= +// ::= eq # == +// ::= ge # >= +// ::= gt # > +// ::= ix # [] +// ::= le # <= +// ::= li # operator "" +// ::= ls # << +// ::= lS # <<= +// ::= lt # < +// ::= mi # - +// ::= mI # -= +// ::= ml # * +// ::= mL # *= +// ::= mm # -- (postfix in context) +// ::= na # new[] +// ::= ne # != +// ::= ng # - (unary) +// ::= nt # ! +// ::= nw # new +// ::= oo # || +// ::= or # | +// ::= oR # |= +// ::= pm # ->* +// ::= pl # + +// ::= pL # += +// ::= pp # ++ (postfix in context) +// ::= ps # + (unary) +// ::= pt # -> +// ::= qu # ? +// ::= rm # % +// ::= rM # %= +// ::= rs # >> +// ::= rS # >>= +// ::= ss # <=> C++2a +// ::= v # vendor extended operator +Node *Db::parseOperatorName(NameState *State) { + switch (look()) { + case 'a': + switch (look(1)) { + case 'a': + First += 2; + return make("operator&&"); + case 'd': + case 'n': + First += 2; + return make("operator&"); + case 'N': + First += 2; + return make("operator&="); + case 'S': + First += 2; + return make("operator="); + } + return nullptr; + case 'c': + switch (look(1)) { + case 'l': + First += 2; + return make("operator()"); + case 'm': + First += 2; + return make("operator,"); + case 'o': + First += 2; + return make("operator~"); + // ::= cv # (cast) + case 'v': { + First += 2; + SwapAndRestore SaveTemplate(TryToParseTemplateArgs, false); + // If we're parsing an encoding, State != nullptr and the conversion + // operators' could have a that refers to some + // s further ahead in the mangled name. + SwapAndRestore SavePermit(PermitForwardTemplateReferences, + PermitForwardTemplateReferences || + State != nullptr); + Node* Ty = parseType(); + if (Ty == nullptr) + return nullptr; + if (State) State->CtorDtorConversion = true; + return make(Ty); + } + } + return nullptr; + case 'd': + switch (look(1)) { + case 'a': + First += 2; + return make("operator delete[]"); + case 'e': + First += 2; + return make("operator*"); + case 'l': + First += 2; + return make("operator delete"); + case 'v': + First += 2; + return make("operator/"); + case 'V': + First += 2; + return make("operator/="); + } + return nullptr; + case 'e': + switch (look(1)) { + case 'o': + First += 2; + return make("operator^"); + case 'O': + First += 2; + return make("operator^="); + case 'q': + First += 2; + return make("operator=="); + } + return nullptr; + case 'g': + switch (look(1)) { + case 'e': + First += 2; + return make("operator>="); + case 't': + First += 2; + return make("operator>"); + } + return nullptr; + case 'i': + if (look(1) == 'x') { + First += 2; + return make("operator[]"); + } + return nullptr; + case 'l': + switch (look(1)) { + case 'e': + First += 2; + return make("operator<="); + // ::= li # operator "" + case 'i': { + First += 2; + Node *SN = parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make(SN); + } + case 's': + First += 2; + return make("operator<<"); + case 'S': + First += 2; + return make("operator<<="); + case 't': + First += 2; + return make("operator<"); + } + return nullptr; + case 'm': + switch (look(1)) { + case 'i': + First += 2; + return make("operator-"); + case 'I': + First += 2; + return make("operator-="); + case 'l': + First += 2; + return make("operator*"); + case 'L': + First += 2; + return make("operator*="); + case 'm': + First += 2; + return make("operator--"); + } + return nullptr; + case 'n': + switch (look(1)) { + case 'a': + First += 2; + return make("operator new[]"); + case 'e': + First += 2; + return make("operator!="); + case 'g': + First += 2; + return make("operator-"); + case 't': + First += 2; + return make("operator!"); + case 'w': + First += 2; + return make("operator new"); + } + return nullptr; + case 'o': + switch (look(1)) { + case 'o': + First += 2; + return make("operator||"); + case 'r': + First += 2; + return make("operator|"); + case 'R': + First += 2; + return make("operator|="); + } + return nullptr; + case 'p': + switch (look(1)) { + case 'm': + First += 2; + return make("operator->*"); + case 'l': + First += 2; + return make("operator+"); + case 'L': + First += 2; + return make("operator+="); + case 'p': + First += 2; + return make("operator++"); + case 's': + First += 2; + return make("operator+"); + case 't': + First += 2; + return make("operator->"); + } + return nullptr; + case 'q': + if (look(1) == 'u') { + First += 2; + return make("operator?"); + } + return nullptr; + case 'r': + switch (look(1)) { + case 'm': + First += 2; + return make("operator%"); + case 'M': + First += 2; + return make("operator%="); + case 's': + First += 2; + return make("operator>>"); + case 'S': + First += 2; + return make("operator>>="); + } + return nullptr; + case 's': + if (look(1) == 's') { + First += 2; + return make("operator<=>"); + } + return nullptr; + // ::= v # vendor extended operator + case 'v': + if (std::isdigit(look(1))) { + First += 2; + Node *SN = parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make(SN); + } + return nullptr; + } + return nullptr; +} + +// ::= C1 # complete object constructor +// ::= C2 # base object constructor +// ::= C3 # complete object allocating constructor +// extension ::= C5 # ? +// ::= D0 # deleting destructor +// ::= D1 # complete object destructor +// ::= D2 # base object destructor +// extension ::= D5 # ? +Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { + if (SoFar->K == Node::KSpecialSubstitution) { + auto SSK = static_cast(SoFar)->SSK; + switch (SSK) { + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + SoFar = make(SSK); + default: + break; + } + } + + if (consumeIf('C')) { + bool IsInherited = consumeIf('I'); + if (look() != '1' && look() != '2' && look() != '3' && look() != '5') + return nullptr; + ++First; + if (State) State->CtorDtorConversion = true; + if (IsInherited) { + if (parseName(State) == nullptr) + return nullptr; + } + return make(SoFar, false); + } + + if (look() == 'D' && + (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) { + First += 2; + if (State) State->CtorDtorConversion = true; + return make(SoFar, true); + } + + return nullptr; +} + +// ::= N [] [] E +// ::= N [] [] E +// +// ::= +// ::= +// ::= +// ::= +// ::= # empty +// ::= +// ::= +// extension ::= L +// +// := [] M +// +// ::=