From b8bf02807e05038b649c13f6e172fa2a4c4f0f8e Mon Sep 17 00:00:00 2001 From: Alfred Bratterud Date: Thu, 30 Mar 2017 11:09:36 +0200 Subject: [PATCH] build: fixes to bundle build using newlib 2.5 --- CMakeLists.txt | 2 +- api/posix/ctype.h | 5 +- api/posix/features.h | 5 + cmake/cross_compiled_libraries.txt | 6 +- etc/build_llvm32.sh | 70 +- etc/build_newlib.sh | 14 +- etc/create_binary_bundle.sh | 54 +- etc/install_from_bundle.sh | 3 +- etc/scripts/qemu_cmd.sh | 1 - etc/service.cmake | 2 +- src/CMakeLists.txt | 8 +- src/arch/x86/start.asm | 4 +- src/crt/cxxabi/abort_message.cpp | 31 - src/crt/cxxabi/abort_message.h | 33 - src/crt/cxxabi/config.h | 30 - src/crt/cxxabi/cxa_aux_runtime.cpp | 39 - src/crt/cxxabi/cxa_default_handlers.cpp | 123 - src/crt/cxxabi/cxa_demangle.cpp | 4969 ---------------------- src/crt/cxxabi/cxa_exception.cpp | 729 ---- src/crt/cxxabi/cxa_exception.hpp | 125 - src/crt/cxxabi/cxa_exception_storage.cpp | 103 - src/crt/cxxabi/cxa_guard.cpp | 260 -- src/crt/cxxabi/cxa_handlers.cpp | 126 - src/crt/cxxabi/cxa_handlers.hpp | 54 - src/crt/cxxabi/cxa_new_delete.cpp | 262 -- src/crt/cxxabi/cxa_personality.cpp | 1298 ------ src/crt/cxxabi/cxa_thread_atexit.cpp | 28 - src/crt/cxxabi/cxa_unexpected.cpp | 27 - src/crt/cxxabi/cxa_vector.cpp | 372 -- src/crt/cxxabi/cxa_virtual.cpp | 31 - src/crt/cxxabi/exception.cpp | 41 - src/crt/cxxabi/fallback_malloc.ipp | 188 - src/crt/cxxabi/private_typeinfo.cpp | 1279 ------ src/crt/cxxabi/private_typeinfo.h | 257 -- src/crt/cxxabi/stdexcept.cpp | 48 - src/crt/cxxabi/typeinfo.cpp | 53 - src/include/__cxxabi_config.h | 20 - src/include/cxxabi.h | 181 - src/kernel/timers.cpp | 22 +- 39 files changed, 102 insertions(+), 10801 deletions(-) delete mode 100644 src/crt/cxxabi/abort_message.cpp delete mode 100644 src/crt/cxxabi/abort_message.h delete mode 100644 src/crt/cxxabi/config.h delete mode 100644 src/crt/cxxabi/cxa_aux_runtime.cpp delete mode 100644 src/crt/cxxabi/cxa_default_handlers.cpp delete mode 100644 src/crt/cxxabi/cxa_demangle.cpp delete mode 100644 src/crt/cxxabi/cxa_exception.cpp delete mode 100644 src/crt/cxxabi/cxa_exception.hpp delete mode 100644 src/crt/cxxabi/cxa_exception_storage.cpp delete mode 100644 src/crt/cxxabi/cxa_guard.cpp delete mode 100644 src/crt/cxxabi/cxa_handlers.cpp delete mode 100644 src/crt/cxxabi/cxa_handlers.hpp delete mode 100644 src/crt/cxxabi/cxa_new_delete.cpp delete mode 100644 src/crt/cxxabi/cxa_personality.cpp delete mode 100644 src/crt/cxxabi/cxa_thread_atexit.cpp delete mode 100644 src/crt/cxxabi/cxa_unexpected.cpp delete mode 100644 src/crt/cxxabi/cxa_vector.cpp delete mode 100644 src/crt/cxxabi/cxa_virtual.cpp delete mode 100644 src/crt/cxxabi/exception.cpp delete mode 100644 src/crt/cxxabi/fallback_malloc.ipp delete mode 100644 src/crt/cxxabi/private_typeinfo.cpp delete mode 100644 src/crt/cxxabi/private_typeinfo.h delete mode 100644 src/crt/cxxabi/stdexcept.cpp delete mode 100644 src/crt/cxxabi/typeinfo.cpp delete mode 100644 src/include/__cxxabi_config.h delete mode 100644 src/include/cxxabi.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e6f63ade35..b104e22f8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ string(STRIP ${OS_VERSION} OS_VERSION) # create random hex string as stack protector canary string(RANDOM LENGTH 8 ALPHABET 0123456789ABCDEF STACK_PROTECTOR_VALUE) -set(CAPABS "-mavx -maes -mfma -fstack-protector-strong -D_STACK_GUARD_VALUE_=0x${STACK_PROTECTOR_VALUE} ") +set(CAPABS "-msse3 -fstack-protector-strong -D_STACK_GUARD_VALUE_=0x${STACK_PROTECTOR_VALUE} ") # Various global defines # * NO_DEBUG disables output from the debug macro diff --git a/api/posix/ctype.h b/api/posix/ctype.h index 0f56e1b3e8..14c882e66b 100644 --- a/api/posix/ctype.h +++ b/api/posix/ctype.h @@ -15,6 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Trick to prevent libc++ from using old newlib locale stubs +#define _LIBCPP_SUPPORT_NEWLIB_XLOCALE_H + + #ifndef SYS_CTYPE_H #define SYS_CTYPE_H @@ -40,5 +44,4 @@ extern "C" { #endif //SYS_CTYPE_H - #include_next diff --git a/api/posix/features.h b/api/posix/features.h index 20ca645ddf..0fc2a44f44 100644 --- a/api/posix/features.h +++ b/api/posix/features.h @@ -27,6 +27,11 @@ #define _POSIX_TIMERS 1 #define _POSIX_MONOTONIC_CLOCK 1 +// Enable newlib multibyte support +#define _MB_CAPABLE 1 + + + // Required to pass CMake tests for libc++ #define __GLIBC_PREREQ__(min, maj) 1 #define __GLIBC_PREREQ(min, maj) 1 diff --git a/cmake/cross_compiled_libraries.txt b/cmake/cross_compiled_libraries.txt index 6872fd36c4..82da0c3dc8 100644 --- a/cmake/cross_compiled_libraries.txt +++ b/cmake/cross_compiled_libraries.txt @@ -32,8 +32,12 @@ set(PRECOMPILED_DIR ${CMAKE_CURRENT_BINARY_DIR}/precompiled/src/PrecompiledLibra set(LIBCXX_INCLUDE_DIR ${PRECOMPILED_DIR}libcxx/include/) set(LIBCXX_LIB_DIR ${PRECOMPILED_DIR}/libcxx/) add_library(libcxx STATIC IMPORTED) +add_library(libcxxabi STATIC IMPORTED) + add_dependencies(libcxx PrecompiledLibraries) +add_dependencies(libcxxabi PrecompiledLibraries) set_target_properties(libcxx PROPERTIES IMPORTED_LOCATION ${LIBCXX_LIB_DIR}/libc++.a) +set_target_properties(libcxxabi PROPERTIES IMPORTED_LOCATION ${LIBCXX_LIB_DIR}/libc++abi.a) set(NEWLIB_INCLUDE_DIR ${PRECOMPILED_DIR}/newlib/include/) set(NEWLIB_LIB_DIR ${PRECOMPILED_DIR}/newlib/) @@ -62,4 +66,4 @@ install(DIRECTORY ${NEWLIB_INCLUDE_DIR} DESTINATION includeos/include/newlib) install(FILES ${CRTEND} ${CRTBEGIN} DESTINATION includeos/lib) -install(FILES ${NEWLIB_LIB_DIR}/libc.a ${NEWLIB_LIB_DIR}/libg.a ${NEWLIB_LIB_DIR}/libm.a ${LIBGCC_LIB_DIR}/libgcc.a ${LIBCXX_LIB_DIR}/libc++.a DESTINATION includeos/lib) +install(FILES ${NEWLIB_LIB_DIR}/libc.a ${NEWLIB_LIB_DIR}/libg.a ${NEWLIB_LIB_DIR}/libm.a ${LIBGCC_LIB_DIR}/libgcc.a ${LIBCXX_LIB_DIR}/libc++.a ${LIBCXX_LIB_DIR}/libc++abi.a DESTINATION includeos/lib) diff --git a/etc/build_llvm32.sh b/etc/build_llvm32.sh index cfc4ed322f..5016722070 100755 --- a/etc/build_llvm32.sh +++ b/etc/build_llvm32.sh @@ -5,7 +5,10 @@ newlib_inc=$TEMP_INSTALL_DIR/i686-elf/include # path for newlib headers IncludeOS_posix=$INCLUDEOS_SRC/api/posix -libcxx_inc=$BUILD_DIR/$llvm_src/projects/libcxx/include +libcxx_inc=$BUILD_DIR/llvm/projects/libcxx/include +libcxxabi_inc=$BUILD_DIR/llvm/projects/libcxxabi/include + +# sysroot=$BUILD_DIR/IncludeOS_TEMP_install/i686-elf # Install dependencies sudo apt-get install -y cmake ninja-build subversion zlib1g-dev libtinfo-dev @@ -19,7 +22,7 @@ if [ ! -z $download_llvm ]; then svn co http://llvm.org/svn/llvm-project/llvm/tags/$LLVM_TAG llvm # Clone libc++, libc++abi, and some extra stuff (recommended / required for clang) - cd llvm/projects + pushd llvm/projects # Compiler-rt svn co http://llvm.org/svn/llvm-project/compiler-rt/tags/$LLVM_TAG compiler-rt @@ -38,7 +41,7 @@ if [ ! -z $download_llvm ]; then #git clone http://llvm.org/git/libunwind # Back to start - cd $BUILD_DIR + popd fi # Make a build-directory @@ -49,44 +52,8 @@ if [ ! -z $clear_llvm_build_cache ]; then rm CMakeCache.txt fi -# General options -OPTS=-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" " - -# LLVM General options -OPTS+=-DBUILD_SHARED_LIBS=OFF" " -OPTS+=-DCMAKE_BUILD_TYPE=MinSizeRel" " - -# Can't build libc++ with g++ unless it's a cross compiler (need to specify target) -OPTS+=-DCMAKE_C_COMPILER=clang-$clang_version" " -OPTS+=-DCMAKE_CXX_COMPILER=clang++-$clang_version" " # -std=c++11" " - TRIPLE=i686-pc-none-elf - -OPTS+=-DTARGET_TRIPLE=$TRIPLE" " -OPTS+=-DLLVM_BUILD_32_BITS=ON" " -OPTS+=-DLLVM_INCLUDE_TESTS=OFF" " -OPTS+=-DLLVM_ENABLE_THREADS=OFF" " -OPTS+=-DLLVM_DEFAULT_TARGET_TRIPLE=$TRIPLE" " - -# libc++-specific options -OPTS+=-DLIBCXX_ENABLE_SHARED=OFF" " -OPTS+=-DLIBCXX_ENABLE_THREADS=OFF" " -OPTS+=-DLIBCXX_TARGET_TRIPLE=$TRIPLE" " -OPTS+=-DLIBCXX_BUILD_32_BITS=ON" " - -OPTS+=-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON" " - -OPTS+=-DLIBCXX_CXX_ABI=libcxxabi" " -OPTS+=-DLIBCXX_CXX_ABI_INCLUDE_PATHS=$INCLUDEOS_SRC/src/include" " - -# libunwind-specific options -OPTS+=-DLIBUNWIND_ENABLE_SHARED=OFF" " -OPTS+=-LIBCXXABI_USE_LLVM_UNWINDER=ON" " - -echo "LLVM CMake Build options:" $OPTS - -# CXX flags -CXX_FLAGS="-std=c++14 -nostdlibinc -mavx -maes -mfma" +CXX_FLAGS="-std=c++14 -msse3" # CMAKE configure step # @@ -94,9 +61,30 @@ CXX_FLAGS="-std=c++14 -nostdlibinc -mavx -maes -mfma" # 1. IncludeOS_posix has to come first, as it provides lots of C11 prototypes that libc++ relies on, but which newlib does not provide (see our math.h) # 2. libcxx_inc must come before newlib, due to math.h function wrappers around C99 macros (signbit, nan etc) # 3. newlib_inc provodes standard C headers -cmake -GNinja $OPTS -DCMAKE_CXX_FLAGS="$CXX_FLAGS -I$IncludeOS_posix -I$libcxx_inc -I$newlib_inc" $BUILD_DIR/llvm +cmake -GNinja $OPTS \ + -DCMAKE_CXX_FLAGS="$CXX_FLAGS -I$IncludeOS_posix -I$libcxxabi_inc -I$libcxx_inc -I$newlib_inc " $BUILD_DIR/llvm \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_C_COMPILER=clang-$clang_version \ + -DCMAKE_CXX_COMPILER=clang++-$clang_version \ + -DTARGET_TRIPLE=$TRIPLE \ + -DLLVM_BUILD_32_BITS=ON \ + -DLLVM_INCLUDE_TESTS=OFF \ + -DLLVM_ENABLE_THREADS=OFF \ + -DLLVM_DEFAULT_TARGET_TRIPLE=$TRIPLE \ + -DLIBCXX_ENABLE_SHARED=OFF \ + -DLIBCXX_ENABLE_THREADS=OFF \ + -DLIBCXX_TARGET_TRIPLE=$TRIPLE \ + -DLIBCXX_BUILD_32_BITS=ON \ + -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \ + -DLIBCXX_CXX_ABI=libcxxabi \ + -DLIBCXXABI_TARGET_TRIPLE=$TRIPLE \ + -DLIBCXXABI_ENABLE_THREADS=OFF \ + -DLIBCXXABI_HAS_PTHREAD_API=OFF + # MAKE +ninja libc++abi.a ninja libc++.a popd diff --git a/etc/build_newlib.sh b/etc/build_newlib.sh index 7bd376f33e..932136a1b1 100755 --- a/etc/build_newlib.sh +++ b/etc/build_newlib.sh @@ -32,10 +32,18 @@ pushd build_newlib --target=$TARGET \ --prefix=$TEMP_INSTALL_DIR \ --enable-newlib-io-long-long AS_FOR_TARGET=as LD_FOR_TARGET=ld AR_FOR_TARGET=ar RANLIB_FOR_TARGET=ranlib \ - -echo -e "\n\n >>> BUILDING NEWLIB \n\n" + --enable-newlib-hw-fp \ + --enable-newlib-mb \ + --enable-newlib-iconv \ + --enable-newlib-iconv-encodings=utf-16,utf-8,ucs_2 \ + --disable-libgloss \ + --disable-multilib \ + --enable-newlib-multithread \ + --disable-newlib-supplied-syscalls + +echo -e "\n\n >>> BUILDING NEWLIB \n\n" # Compile -make $num_jobs all +make $num_jobs all # Install make install diff --git a/etc/create_binary_bundle.sh b/etc/create_binary_bundle.sh index 08e8b8a089..ed60c97166 100755 --- a/etc/create_binary_bundle.sh +++ b/etc/create_binary_bundle.sh @@ -9,13 +9,14 @@ export PATH="$TEMP_INSTALL_DIR/bin:$PATH" # Build options export TARGET=i686-elf # Configure target -export num_jobs=${num_jobs:-"-j"} # Specify number of build jobs +export num_jobs=${num_jobs:-"-j"} # Specify number of build jobs # Version numbers -export binutils_version=${binutils_version:-2.26} # ftp://ftp.gnu.org/gnu/binutils -export newlib_version=${newlib_version:-2.4.0} # ftp://sourceware.org/pub/newlib -export gcc_version=${gcc_version:-6.2.0} # ftp://ftp.nluug.nl/mirror/languages/gcc/releases/ -export clang_version=${clang_version:-3.8} # http://releases.llvm.org/ +export binutils_version=${binutils_version:-2.28} # ftp://ftp.gnu.org/gnu/binutils +export newlib_version=${newlib_version:-2.5.0.20170323} # ftp://sourceware.org/pub/newlib +#export newlib_version=${newlib_version:-2.5.0} # ftp://sourceware.org/pub/newlib +export gcc_version=${gcc_version:-6.3.0} # ftp://ftp.nluug.nl/mirror/languages/gcc/releases/ +export clang_version=${clang_version:-3.9} # http://releases.llvm.org/ export LLVM_TAG=${LLVM_TAG:-RELEASE_381/final} # http://llvm.org/svn/llvm-project/llvm/tags # Options to skip steps @@ -50,8 +51,11 @@ DEPS_BUILD="build-essential make nasm texinfo clang-$clang_version clang++-$clan echo -e "\n\n >>> Trying to install prerequisites for *building* IncludeOS" echo -e " Packages: $DEPS_BUILD \n" -sudo apt-get update -sudo apt-get install -y $DEPS_BUILD + +if [ ! -z $do_packages ]; then + sudo apt-get update + sudo apt-get install -y $DEPS_BUILD +fi # Print currently set install options printf "\n\n>>> Bundle will be created with the following options:\n\n" @@ -113,10 +117,10 @@ filename_tag=`echo $tag | tr . -` popd # Where to place the installation bundle -DIR_NAME="IncludeOS_install" -export INSTALL_DIR=${INSTALL_DIR:-~/$DIR_NAME} +DIR_NAME="IncludeOS_dependencies" +export BUNDLE_DIR=${BUNDLE_DIR:-~/$DIR_NAME} -echo ">>> Creating Installation Bundle as $INSTALL_DIR" +echo ">>> Creating Installation Bundle as $BUNDLE_DIR" OUTFILE="${DIR_NAME}_$filename_tag.tar.gz" @@ -128,6 +132,7 @@ libc=$newlib/libc.a libm=$newlib/libm.a libg=$newlib/libg.a libcpp=$llvm/lib/libc++.a +libcppabi=$llvm/lib/libc++abi.a GPP=$TEMP_INSTALL_DIR/bin/i686-elf-g++ GCC_VER=`$GPP -dumpversion` @@ -138,26 +143,27 @@ include_newlib=$TEMP_INSTALL_DIR/i686-elf/include include_libcxx=$llvm/include/c++/v1 # Make directory-tree -mkdir -p $INSTALL_DIR -mkdir -p $INSTALL_DIR/newlib -mkdir -p $INSTALL_DIR/libcxx -mkdir -p $INSTALL_DIR/crt -mkdir -p $INSTALL_DIR/libgcc +mkdir -p $BUNDLE_DIR +mkdir -p $BUNDLE_DIR/newlib +mkdir -p $BUNDLE_DIR/libcxx +mkdir -p $BUNDLE_DIR/crt +mkdir -p $BUNDLE_DIR/libgcc # Copy binaries -cp $libcpp $INSTALL_DIR/libcxx/ -cp $libm $INSTALL_DIR/newlib/ -cp $libc $INSTALL_DIR/newlib/ -cp $libg $INSTALL_DIR/newlib/ -cp $libgcc $INSTALL_DIR/libgcc/ -cp $TEMP_INSTALL_DIR/lib/gcc/i686-elf/$GCC_VER/crt*.o $INSTALL_DIR/crt/ +cp $libcpp $BUNDLE_DIR/libcxx/ +cp $libcppabi $BUNDLE_DIR/libcxx/ +cp $libm $BUNDLE_DIR/newlib/ +cp $libc $BUNDLE_DIR/newlib/ +cp $libg $BUNDLE_DIR/newlib/ +cp $libgcc $BUNDLE_DIR/libgcc/ +cp $TEMP_INSTALL_DIR/lib/gcc/i686-elf/$GCC_VER/crt*.o $BUNDLE_DIR/crt/ # Copy includes -cp -r $include_newlib $INSTALL_DIR/newlib/ -cp -r $include_libcxx $INSTALL_DIR/libcxx/include +cp -r $include_newlib $BUNDLE_DIR/newlib/ +cp -r $include_libcxx $BUNDLE_DIR/libcxx/include # Zip it -tar -czvf $OUTFILE --directory=$INSTALL_DIR/../ $DIR_NAME +tar -czvf $OUTFILE --directory=$BUNDLE_DIR/../ $DIR_NAME echo ">>> IncludeOS Installation Bundle created as $INSTALL_DIR and gzipped into $OUTFILE" diff --git a/etc/install_from_bundle.sh b/etc/install_from_bundle.sh index 49475ffdcc..c5adb52944 100755 --- a/etc/install_from_bundle.sh +++ b/etc/install_from_bundle.sh @@ -15,6 +15,7 @@ set -e INCLUDEOS_SRC=${INCLUDEOS_SRC-$HOME/IncludeOS} INCLUDEOS_PREFIX=${INCLUDEOS_PREFIX-/usr/local} +num_jobs=${num_jobs-"-j 4"} # Try to find suitable compiler cc_list="clang-3.9 clang-3.8 clang-3.7 clang-3.6 clang" @@ -54,7 +55,7 @@ cmake $INCLUDEOS_SRC \ -Dtests=$INCLUDEOS_ENABLE_TEST \ -DBUNDLE_LOC=$BUNDLE_LOC make PrecompiledLibraries -make -j 4 +make $num_jobs make install popd diff --git a/etc/scripts/qemu_cmd.sh b/etc/scripts/qemu_cmd.sh index 0f1c0fc0c8..869b942c7b 100755 --- a/etc/scripts/qemu_cmd.sh +++ b/etc/scripts/qemu_cmd.sh @@ -3,7 +3,6 @@ if [ "$(egrep -m 1 '^flags.*(vmx|svm)' /proc/cpuinfo)" ] then echo ">>> KVM: ON " export QEMU="qemu-system-x86_64 --enable-kvm" - export CPU="-cpu host" else echo ">>> KVM: OFF " export QEMU="qemu-system-i386" diff --git a/etc/service.cmake b/etc/service.cmake index 64973f2147..71edb261a4 100644 --- a/etc/service.cmake +++ b/etc/service.cmake @@ -25,7 +25,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_ASM_NASM_OBJECT_FORMAT "elf") enable_language(ASM_NASM) -set(CAPABS "-mavx -maes -mfma -fstack-protector-strong") +set(CAPABS "-msse3 -fstack-protector-strong") # Various global defines # * OS_TERMINATE_ON_CONTRACT_VIOLATION provides classic assert-like output from Expects / Ensures diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90163c1461..d29d77c7af 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,18 +72,12 @@ set(OS_OBJECTS add_library(os STATIC ${OS_OBJECTS} apic_boot.o) add_dependencies(os PrecompiledLibraries botan) -file(GLOB CXX_ABI crt/cxxabi/*.cpp) - -add_library(c++abi STATIC ${CXX_ABI}) -add_dependencies(c++abi libcxx) - add_subdirectory(crt) add_subdirectory(boot) add_subdirectory(drivers) add_subdirectory(plugins) -install(TARGETS c++abi os DESTINATION includeos/lib) - +install(TARGETS os DESTINATION includeos/lib) install(DIRECTORY ${INCLUDEOS_ROOT}/src/memdisk/ DESTINATION includeos/memdisk FILES_MATCHING PATTERN "*.*") diff --git a/src/arch/x86/start.asm b/src/arch/x86/start.asm index 7ed8df6707..1de3cbf2b2 100644 --- a/src/arch/x86/start.asm +++ b/src/arch/x86/start.asm @@ -50,9 +50,9 @@ rock_bottom: ;; enable SSE before we enter C/C++ land call enable_sse ;; ... and XSAVE to get xsetbv/xgetbv working - call enable_xsave + ;; call enable_xsave ;; ... and finally, enable AVX - call enable_avx + ;; call enable_avx ;; Place multiboot parameters on stack push ebx diff --git a/src/crt/cxxabi/abort_message.cpp b/src/crt/cxxabi/abort_message.cpp deleted file mode 100644 index ceef3d52bc..0000000000 --- a/src/crt/cxxabi/abort_message.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===------------------------- 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" -#include "config.h" - -#pragma GCC visibility push(hidden) - -__attribute__((visibility("hidden"), noreturn)) -void abort_message(const char* format, ...) -{ - // record message and call syscall abort_ex - char* buffer; - va_list list; - va_start(list, format); - vasprintf(&buffer, format, list); - va_end(list); - - abort_ex(buffer); -} - -#pragma GCC visibility pop diff --git a/src/crt/cxxabi/abort_message.h b/src/crt/cxxabi/abort_message.h deleted file mode 100644 index 2c5cb20466..0000000000 --- a/src/crt/cxxabi/abort_message.h +++ /dev/null @@ -1,33 +0,0 @@ -//===-------------------------- 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 - -#pragma GCC visibility push(hidden) - -#ifdef __cplusplus -extern "C" { -#endif - -__attribute__((visibility("hidden"), noreturn)) - void abort_message(const char* format, ...) - __attribute__((format(printf, 1, 2))); - - -#ifdef __cplusplus -} -#endif - -#pragma GCC visibility pop - -#endif - diff --git a/src/crt/cxxabi/config.h b/src/crt/cxxabi/config.h deleted file mode 100644 index ba6204b233..0000000000 --- a/src/crt/cxxabi/config.h +++ /dev/null @@ -1,30 +0,0 @@ -//===----------------------------- 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. -// -// -// Defines macros used within the libc++abi project. -// -//===----------------------------------------------------------------------===// - - -#ifndef LIBCXXABI_CONFIG_H -#define LIBCXXABI_CONFIG_H - -#include - -// much better than abort() -void abort_ex(const char*) __attribute__((noreturn)); - -// Set this in the CXXFLAGS when you need it -#define LIBCXXABI_HAS_NO_THREADS 1 - -// Set this in the CXXFLAGS when you need it, because otherwise we'd have to -// #if !defined(__linux__) && !defined(__APPLE__) && ... -// and so-on for *every* platform. -#define LIBCXXABI_BAREMETAL 1 - -#endif // LIBCXXABI_CONFIG_H diff --git a/src/crt/cxxabi/cxa_aux_runtime.cpp b/src/crt/cxxabi/cxa_aux_runtime.cpp deleted file mode 100644 index 7fec810fb7..0000000000 --- a/src/crt/cxxabi/cxa_aux_runtime.cpp +++ /dev/null @@ -1,39 +0,0 @@ -//===------------------------ 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_NORETURN -void __cxa_bad_cast (void) { - throw std::bad_cast(); -} - -LIBCXXABI_NORETURN -void __cxa_bad_typeid(void) { - throw std::bad_typeid(); -} - -LIBCXXABI_NORETURN -void __cxa_throw_bad_array_new_length(void) { - throw std::bad_array_new_length(); -} -} // extern "C" - -} // abi diff --git a/src/crt/cxxabi/cxa_default_handlers.cpp b/src/crt/cxxabi/cxa_default_handlers.cpp deleted file mode 100644 index d34341aa32..0000000000 --- a/src/crt/cxxabi/cxa_default_handlers.cpp +++ /dev/null @@ -1,123 +0,0 @@ -//===------------------------- 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 "abort_message.h" -#include "config.h" // For __sync_swap -#include "cxxabi.h" -#include "cxa_handlers.hpp" -#include "cxa_exception.hpp" -#include "private_typeinfo.h" - -static const char* cause = "uncaught"; - -__attribute__((noreturn)) -static void default_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 default_unexpected_handler() -{ - cause = "unexpected"; - std::terminate(); -} - - -// -// Global variables that hold the pointers to the current handler -// -std::terminate_handler __cxa_terminate_handler = default_terminate_handler; -std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; - -// In the future these will become: -// std::atomic __cxa_terminate_handler(default_terminate_handler); -// std::atomic __cxa_unexpected_handler(default_unexpected_handler); - -namespace std -{ - -unexpected_handler -set_unexpected(unexpected_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_unexpected_handler; - return __atomic_exchange_n(&__cxa_unexpected_handler, func, - __ATOMIC_ACQ_REL); -// Using of C++11 atomics this should be rewritten -// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel); -} - -terminate_handler -set_terminate(terminate_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_terminate_handler; - return __atomic_exchange_n(&__cxa_terminate_handler, func, - __ATOMIC_ACQ_REL); -// Using of C++11 atomics this should be rewritten -// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel); -} - -} diff --git a/src/crt/cxxabi/cxa_demangle.cpp b/src/crt/cxxabi/cxa_demangle.cpp deleted file mode 100644 index 5966faa0b8..0000000000 --- a/src/crt/cxxabi/cxa_demangle.cpp +++ /dev/null @@ -1,4969 +0,0 @@ -//===-------------------------- 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. -// -//===----------------------------------------------------------------------===// - -#define _LIBCPP_EXTERN_TEMPLATE(...) -#define _LIBCPP_NO_EXCEPTIONS - -#include -#include -#include -#include -#include -#include -#include - -namespace __cxxabiv1 -{ - -namespace -{ - -enum -{ - unknown_error = -4, - invalid_args = -3, - invalid_mangled_name, - memory_alloc_failure, - success -}; - -template - const char* parse_type(const char* first, const char* last, C& db); -template - const char* parse_encoding(const char* first, const char* last, C& db); -template - const char* parse_name(const char* first, const char* last, C& db, - bool* ends_with_template_args = 0); -template - const char* parse_expression(const char* first, const char* last, C& db); -template - const char* parse_template_args(const char* first, const char* last, C& db); -template - const char* parse_operator_name(const char* first, const char* last, C& db); -template - const char* parse_unqualified_name(const char* first, const char* last, C& db); -template - const char* parse_decltype(const char* first, const char* last, C& db); - -template -void -print_stack(const C& db) -{ - fprintf(stderr, "---------\n"); - fprintf(stderr, "names:\n"); - for (auto& s : db.names) - fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str()); - int i = -1; - fprintf(stderr, "subs:\n"); - for (auto& v : db.subs) - { - if (i >= 0) - fprintf(stderr, "S%i_ = {", i); - else - fprintf(stderr, "S_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } - fprintf(stderr, "template_param:\n"); - for (auto& t : db.template_param) - { - fprintf(stderr, "--\n"); - i = -1; - for (auto& v : t) - { - if (i >= 0) - fprintf(stderr, "T%i_ = {", i); - else - fprintf(stderr, "T_ = {"); - for (auto& s : v) - fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str()); - fprintf(stderr, "}\n"); - ++i; - } - } - fprintf(stderr, "---------\n\n"); -} - -template -void -print_state(const char* msg, const char* first, const char* last, const C& db) -{ - fprintf(stderr, "%s: ", msg); - for (; first != last; ++first) - fprintf(stderr, "%c", *first); - fprintf(stderr, "\n"); - print_stack(db); -} - -// ::= [n] - -const char* -parse_number(const char* first, const char* last) -{ - if (first != last) - { - const char* t = first; - if (*t == 'n') - ++t; - if (t != last) - { - if (*t == '0') - { - first = t+1; - } - else if ('1' <= *t && *t <= '9') - { - first = t+1; - while (first != last && std::isdigit(*first)) - ++first; - } - } - } - return first; -} - -template -struct float_data; - -template <> -struct float_data -{ - static const size_t mangled_size = 8; - static const size_t max_demangled_size = 24; - static constexpr const char* spec = "%af"; -}; - -constexpr const char* float_data::spec; - -template <> -struct float_data -{ - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static constexpr const char* spec = "%a"; -}; - -constexpr const char* float_data::spec; - -template <> -struct float_data -{ -#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) - static const size_t mangled_size = 32; -#elif defined(__arm__) || defined(__mips__) - static const size_t mangled_size = 16; -#else - static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms -#endif - static const size_t max_demangled_size = 40; - static constexpr const char* spec = "%LaL"; -}; - -constexpr const char* float_data::spec; - -template -const char* -parse_floating_number(const char* first, const char* last, C& db) -{ - const size_t N = float_data::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) - { - if (!isxdigit(*t)) - return first; - unsigned d1 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast(*t - '0') : - static_cast(*t - 'a' + 10); - *e = static_cast((d1 << 4) + d0); - } - if (*t == 'E') - { -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[float_data::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), float_data::spec, value); - if (static_cast(n) >= sizeof(num)) - return first; - db.names.push_back(typename C::String(num, static_cast(n))); - first = t+1; - } - } - return first; -} - -// ::= - -template -const char* -parse_source_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - char c = *first; - if (isdigit(c) && first+1 != last) - { - const char* t = first+1; - size_t n = static_cast(c - '0'); - for (c = *t; isdigit(c); c = *t) - { - n = n * 10 + static_cast(c - '0'); - if (++t == last) - return first; - } - if (static_cast(last - t) >= n) - { - typename C::String r(t, n); - if (r.substr(0, 10) == "_GLOBAL__N") - db.names.push_back("(anonymous namespace)"); - else - db.names.push_back(std::move(r)); - first = t + n; - } - } - } - return first; -} - -// ::= S _ -// ::= S_ -// ::= Sa # ::std::allocator -// ::= Sb # ::std::basic_string -// ::= Ss # ::std::basic_string < char, -// ::std::char_traits, -// ::std::allocator > -// ::= Si # ::std::basic_istream > -// ::= So # ::std::basic_ostream > -// ::= Sd # ::std::basic_iostream > - -template -const char* -parse_substitution(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if (*first == 'S') - { - switch (first[1]) - { - case 'a': - db.names.push_back("std::allocator"); - first += 2; - break; - case 'b': - db.names.push_back("std::basic_string"); - first += 2; - break; - case 's': - db.names.push_back("std::string"); - first += 2; - break; - case 'i': - db.names.push_back("std::istream"); - first += 2; - break; - case 'o': - db.names.push_back("std::ostream"); - first += 2; - break; - case 'd': - db.names.push_back("std::iostream"); - first += 2; - break; - case '_': - if (!db.subs.empty()) - { - for (const auto& n : db.subs.front()) - db.names.push_back(n); - first += 2; - } - break; - default: - if (std::isdigit(first[1]) || std::isupper(first[1])) - { - size_t sub = 0; - const char* t = first+1; - if (std::isdigit(*t)) - sub = static_cast(*t - '0'); - else - sub = static_cast(*t - 'A') + 10; - for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) - { - sub *= 36; - if (std::isdigit(*t)) - sub += static_cast(*t - '0'); - else - sub += static_cast(*t - 'A') + 10; - } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < db.subs.size()) - { - for (const auto& n : db.subs[sub]) - db.names.push_back(n); - first = t+1; - } - } - break; - } - } - } - return first; -} - -// ::= v # void -// ::= w # wchar_t -// ::= b # bool -// ::= c # char -// ::= a # signed char -// ::= h # unsigned char -// ::= s # short -// ::= t # unsigned short -// ::= i # int -// ::= j # unsigned int -// ::= l # long -// ::= m # unsigned long -// ::= x # long long, __int64 -// ::= y # unsigned long long, __int64 -// ::= n # __int128 -// ::= o # unsigned __int128 -// ::= f # float -// ::= d # double -// ::= e # long double, __float80 -// ::= g # __float128 -// ::= z # ellipsis -// ::= Dd # IEEE 754r decimal floating point (64 bits) -// ::= De # IEEE 754r decimal floating point (128 bits) -// ::= Df # IEEE 754r decimal floating point (32 bits) -// ::= Dh # IEEE 754r half-precision floating point (16 bits) -// ::= Di # char32_t -// ::= Ds # char16_t -// ::= Da # auto (in dependent new-expressions) -// ::= Dc # decltype(auto) -// ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) -// ::= u # vendor extended type - -template -const char* -parse_builtin_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - switch (*first) - { - case 'v': - db.names.push_back("void"); - ++first; - break; - case 'w': - db.names.push_back("wchar_t"); - ++first; - break; - case 'b': - db.names.push_back("bool"); - ++first; - break; - case 'c': - db.names.push_back("char"); - ++first; - break; - case 'a': - db.names.push_back("signed char"); - ++first; - break; - case 'h': - db.names.push_back("unsigned char"); - ++first; - break; - case 's': - db.names.push_back("short"); - ++first; - break; - case 't': - db.names.push_back("unsigned short"); - ++first; - break; - case 'i': - db.names.push_back("int"); - ++first; - break; - case 'j': - db.names.push_back("unsigned int"); - ++first; - break; - case 'l': - db.names.push_back("long"); - ++first; - break; - case 'm': - db.names.push_back("unsigned long"); - ++first; - break; - case 'x': - db.names.push_back("long long"); - ++first; - break; - case 'y': - db.names.push_back("unsigned long long"); - ++first; - break; - case 'n': - db.names.push_back("__int128"); - ++first; - break; - case 'o': - db.names.push_back("unsigned __int128"); - ++first; - break; - case 'f': - db.names.push_back("float"); - ++first; - break; - case 'd': - db.names.push_back("double"); - ++first; - break; - case 'e': - db.names.push_back("long double"); - ++first; - break; - case 'g': - db.names.push_back("__float128"); - ++first; - break; - case 'z': - db.names.push_back("..."); - ++first; - break; - case 'u': - { - const char*t = parse_source_name(first+1, last, db); - if (t != first+1) - first = t; - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) - { - case 'd': - db.names.push_back("decimal64"); - first += 2; - break; - case 'e': - db.names.push_back("decimal128"); - first += 2; - break; - case 'f': - db.names.push_back("decimal32"); - first += 2; - break; - case 'h': - db.names.push_back("decimal16"); - first += 2; - break; - case 'i': - db.names.push_back("char32_t"); - first += 2; - break; - case 's': - db.names.push_back("char16_t"); - first += 2; - break; - case 'a': - db.names.push_back("auto"); - first += 2; - break; - case 'c': - db.names.push_back("decltype(auto)"); - first += 2; - break; - case 'n': - db.names.push_back("std::nullptr_t"); - first += 2; - break; - } - } - break; - } - } - return first; -} - -// ::= [r] [V] [K] - -const char* -parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) -{ - cv = 0; - if (first != last) - { - if (*first == 'r') - { - cv |= 4; - ++first; - } - if (*first == 'V') - { - cv |= 2; - ++first; - } - if (*first == 'K') - { - cv |= 1; - ++first; - } - } - return first; -} - -// ::= T_ # first template parameter -// ::= T _ - -template -const char* -parse_template_param(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if (*first == 'T') - { - if (first[1] == '_') - { - if (db.template_param.empty()) - return first; - if (!db.template_param.back().empty()) - { - for (auto& t : db.template_param.back().front()) - db.names.push_back(t); - first += 2; - } - else - { - db.names.push_back("T_"); - first += 2; - db.fix_forward_references = true; - } - } - else if (isdigit(first[1])) - { - const char* t = first+1; - size_t sub = static_cast(*t - '0'); - for (++t; t != last && isdigit(*t); ++t) - { - sub *= 10; - sub += static_cast(*t - '0'); - } - if (t == last || *t != '_' || db.template_param.empty()) - return first; - ++sub; - if (sub < db.template_param.back().size()) - { - for (auto& temp : db.template_param.back()[sub]) - db.names.push_back(temp); - first = t+1; - } - else - { - db.names.push_back(typename C::String(first, t+1)); - first = t+1; - db.fix_forward_references = true; - } - } - } - } - return first; -} - -// cc # const_cast (expression) - -template -const char* -parse_const_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// dc # dynamic_cast (expression) - -template -const char* -parse_dynamic_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// rc # reinterpret_cast (expression) - -template -const char* -parse_reinterpret_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// sc # static_cast (expression) - -template -const char* -parse_static_cast_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; - first = t1; - } - } - } - return first; -} - -// sp # pack expansion - -template -const char* -parse_pack_expansion(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'p') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - first = t; - } - return first; -} - -// st # sizeof (a type) - -template -const char* -parse_sizeof_type_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// sz # sizeof (a expression) - -template -const char* -parse_sizeof_expr_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// sZ # size of a parameter pack - -template -const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') - { - size_t k0 = db.names.size(); - const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) - { - typename C::String tmp("sizeof...("); - size_t k = k0; - if (k != k1) - { - tmp += db.names[k].move_full(); - for (++k; k != k1; ++k) - tmp += ", " + db.names[k].move_full(); - } - tmp += ")"; - for (; k1 != k0; --k1) - db.names.pop_back(); - db.names.push_back(std::move(tmp)); - first = t; - } - } - return first; -} - -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p _ # L > 0, second and later parameters - -template -const char* -parse_function_param(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && *first == 'f') - { - if (first[1] == 'p') - { - unsigned cv; - const char* t = parse_cv_qualifiers(first+2, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.names.push_back("fp" + typename C::String(t, t1)); - first = t1+1; - } - } - else if (first[1] == 'L') - { - unsigned cv; - const char* t0 = parse_number(first+2, last); - if (t0 != last && *t0 == 'p') - { - ++t0; - const char* t = parse_cv_qualifiers(t0, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.names.push_back("fp" + typename C::String(t, t1)); - first = t1+1; - } - } - } - } - return first; -} - -// sZ # size of a function parameter pack - -template -const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') - { - const char* t = parse_function_param(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// te # typeid (expression) -// ti # typeid (type) - -template -const char* -parse_typeid_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) - { - const char* t; - if (first[1] == 'e') - t = parse_expression(first+2, last, db); - else - t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "typeid(" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// tw # throw expression - -template -const char* -parse_throw_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "throw " + db.names.back().move_full(); - first = t; - } - } - return first; -} - -// ds # expr.*expr - -template -const char* -parse_dot_star_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 's') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto expr = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += ".*" + expr; - first = t1; - } - } - } - return first; -} - -// ::= [ ] - -template -const char* -parse_simple_id(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = parse_source_name(first, last, db); - if (t != first) - { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - first = t1; - } - else - first = t; - } - return first; -} - -// ::= -// ::= -// ::= - -template -const char* -parse_unresolved_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = first; - switch (*first) - { - case 'T': - { - size_t k0 = db.names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); - if (t != first && k1 == k0 + 1) - { - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - else - { - for (; k1 != k0; --k1) - db.names.pop_back(); - } - break; - } - case 'D': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - break; - case 'S': - t = parse_substitution(first, last, db); - if (t != first) - first = t; - else - { - if (last - first > 2 && first[1] == 't') - { - t = parse_unqualified_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "std::"); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - } - break; - } - } - return first; -} - -// ::= # e.g., ~T or ~decltype(f()) -// ::= # e.g., ~A<2*N> - -template -const char* -parse_destructor_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t = parse_unresolved_type(first, last, db); - if (t == first) - t = parse_simple_id(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "~"); - first = t; - } - } - return first; -} - -// ::= # unresolved name -// extension ::= # unresolved operator-function-id -// extension ::= # unresolved operator template-id -// ::= on # unresolved operator-function-id -// ::= on # unresolved operator template-id -// ::= dn # destructor or pseudo-destructor; -// # e.g. ~X or ~X - -template -const char* -parse_base_unresolved_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') - { - if (first[0] == 'o') - { - const char* t = parse_operator_name(first+2, last, db); - if (t != first+2) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - } - } - else - { - const char* t = parse_destructor_name(first+2, last, db); - if (t != first+2) - first = t; - } - } - else - { - const char* t = parse_simple_id(first, last, db); - if (t == first) - { - t = parse_operator_name(first, last, db); - if (t != first) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - } - } - } - else - first = t; - } - } - return first; -} - -// ::= - -template -const char* -parse_unresolved_qualifier_level(const char* first, const char* last, C& db) -{ - return parse_simple_id(first, last, db); -} - -// -// extension ::= srN [] * E -// ::= [gs] # x or (with "gs") ::x -// ::= [gs] sr + E -// # A::x, N::y, A::z; "gs" means leading "::" -// ::= sr # T::x / decltype(p)::x -// extension ::= sr -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN + E - -template -const char* -parse_unresolved_name(const char* first, const char* last, C& db) -{ - if (last - first > 2) - { - const char* t = first; - bool global = false; - if (t[0] == 'g' && t[1] == 's') - { - global = true; - t += 2; - } - const char* t2 = parse_base_unresolved_name(t, last, db); - if (t2 != t) - { - if (global) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "::"); - } - first = t2; - } - else if (last - t > 2 && t[0] == 's' && t[1] == 'r') - { - if (t[2] == 'N') - { - t += 3; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - t = t1; - if (t == last) - { - db.names.pop_back(); - return first; - } - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - else - { - t += 2; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 != t) - { - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - t = t1; - } - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - else - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - if (global) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "::"); - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.names.empty()) - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto s = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "::" + std::move(s); - first = t1; - } - } - } - } - return first; -} - -// dt # expr.name - -template -const char* -parse_dot_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_unresolved_name(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto name = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "." + name; - first = t1; - } - } - } - return first; -} - -// cl + E # call - -template -const char* -parse_call_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (t == last) - return first; - if (db.names.empty()) - return first; - db.names.back().first += db.names.back().second; - db.names.back().second = typename C::String(); - db.names.back().first.append("("); - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - if (!first_expr) - { - db.names.back().first.append(", "); - first_expr = false; - } - db.names.back().first.append(tmp); - } - t = t1; - } - ++t; - if (db.names.empty()) - return first; - db.names.back().first.append(")"); - first = t; - } - } - return first; -} - -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization - -template -const char* -parse_new_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 4) - { - const char* t = first; - bool parsed_gs = false; - if (t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) - { - bool is_array = t[1] == 'a'; - t += 2; - if (t == last) - return first; - bool has_expr_list = false; - bool first_expr = true; - while (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - has_expr_list = true; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - ++t; - const char* t1 = parse_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - bool has_init = false; - if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') - { - t += 2; - has_init = true; - first_expr = true; - while (*t != 'E') - { - t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - } - if (*t != 'E') - return first; - typename C::String init_list; - if (has_init) - { - if (db.names.empty()) - return first; - init_list = db.names.back().move_full(); - db.names.pop_back(); - } - if (db.names.empty()) - return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - typename C::String expr_list; - if (has_expr_list) - { - if (db.names.empty()) - return first; - expr_list = db.names.back().move_full(); - db.names.pop_back(); - } - typename C::String r; - if (parsed_gs) - r = "::"; - if (is_array) - r += "[] "; - else - r += " "; - if (has_expr_list) - r += "(" + expr_list + ") "; - r += type; - if (has_init) - r += " (" + init_list + ")"; - db.names.push_back(std::move(r)); - first = t+1; - } - } - return first; -} - -// cv # conversion with one argument -// cv _ * E # conversion with a different number of arguments - -template -const char* -parse_conversion_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') - { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; - const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; - if (t != first+2 && t != last) - { - if (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t) - return first; - t = t1; - } - else - { - ++t; - if (t == last) - return first; - if (*t == 'E') - db.names.emplace_back(); - else - { - bool first_expr = true; - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - if (!first_expr) - { - if (db.names.empty()) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - if (db.names.empty()) - return first; - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - first_expr = false; - } - } - t = t1; - } - } - ++t; - } - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; - first = t; - } - } - return first; -} - -// pt # expr->name - -template -const char* -parse_arrow_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'p' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += "->"; - db.names.back().first += tmp; - first = t1; - } - } - } - return first; -} - -// ::= R # & ref-qualifier -// ::= O # && ref-qualifier - -// ::= F [Y] [] E - -template -const char* -parse_function_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'F') - { - const char* t = first+1; - if (t != last) - { - if (*t == 'Y') - { - /* extern "C" */ - if (++t == last) - return first; - } - const char* t1 = parse_type(t, last, db); - if (t1 != t) - { - t = t1; - typename C::String sig("("); - int ref_qual = 0; - while (true) - { - if (t == last) - { - db.names.pop_back(); - return first; - } - if (*t == 'E') - { - ++t; - break; - } - if (*t == 'v') - { - ++t; - continue; - } - if (*t == 'R' && t+1 != last && t[1] == 'E') - { - ref_qual = 1; - ++t; - continue; - } - if (*t == 'O' && t+1 != last && t[1] == 'E') - { - ref_qual = 2; - ++t; - continue; - } - size_t k0 = db.names.size(); - t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 == t || t1 == last) - return first; - for (size_t k = k0; k < k1; ++k) - { - if (sig.size() > 1) - sig += ", "; - sig += db.names[k].move_full(); - } - for (size_t k = k0; k < k1; ++k) - db.names.pop_back(); - t = t1; - } - sig += ")"; - switch (ref_qual) - { - case 1: - sig += " &"; - break; - case 2: - sig += " &&"; - break; - } - if (db.names.empty()) - return first; - db.names.back().first += " "; - db.names.back().second.insert(0, sig); - first = t; - } - } - } - return first; -} - -// ::= M - -template -const char* -parse_pointer_to_member_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'M') - { - const char* t = parse_type(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto func = std::move(db.names.back()); - db.names.pop_back(); - auto class_type = std::move(db.names.back()); - if (!func.second.empty() && func.second.front() == '(') - { - db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; - db.names.back().second = ")" + std::move(func.second); - } - else - { - db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; - db.names.back().second = std::move(func.second); - } - first = t2; - } - } - } - return first; -} - -// ::= A _ -// ::= A [] _ - -template -const char* -parse_array_type(const char* first, const char* last, C& db) -{ - if (first != last && *first == 'A' && first+1 != last) - { - if (first[1] == '_') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " []"); - first = t; - } - } - else if ('1' <= first[1] && first[1] <= '9') - { - const char* t = parse_number(first+1, last); - if (t != last && *t == '_') - { - const char* t2 = parse_type(t+1, last, db); - if (t2 != t+1) - { - if (db.names.empty()) - return first; - if (db.names.back().second.substr(0, 2) == " [") - db.names.back().second.erase(0, 1); - db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); - first = t2; - } - } - } - else - { - const char* t = parse_expression(first+1, last, db); - if (t != first+1 && t != last && *t == '_') - { - const char* t2 = parse_type(++t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto type = std::move(db.names.back()); - db.names.pop_back(); - auto expr = std::move(db.names.back()); - db.names.back().first = std::move(type.first); - if (type.second.substr(0, 2) == " [") - type.second.erase(0, 1); - db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); - first = t2; - } - } - } - } - return first; -} - -// ::= Dt E # decltype of an id-expression or class member access (C++0x) -// ::= DT E # decltype of an expression (C++0x) - -template -const char* -parse_decltype(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && first[0] == 'D') - { - switch (first[1]) - { - case 't': - case 'T': - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2 && t != last && *t == 'E') - { - if (db.names.empty()) - return first; - db.names.back() = "decltype(" + db.names.back().move_full() + ")"; - first = t+1; - } - } - break; - } - } - return first; -} - -// extension: -// ::= Dv _ -// -// ::= Dv [] _ -// ::= -// ::= p # AltiVec vector pixel - -template -const char* -parse_vector_type(const char* first, const char* last, C& db) -{ - if (last - first > 3 && first[0] == 'D' && first[1] == 'v') - { - if ('1' <= first[2] && first[2] <= '9') - { - const char* t = parse_number(first+2, last); - if (t == last || *t != '_') - return first; - const char* num = first + 2; - size_t sz = static_cast(t - num); - if (++t != last) - { - if (*t != 'p') - { - const char* t1 = parse_type(t, last, db); - if (t1 != t) - { - if (db.names.empty()) - return first; - db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; - first = t1; - } - } - else - { - ++t; - db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); - first = t; - } - } - } - else - { - typename C::String num; - const char* t1 = first+2; - if (*t1 != '_') - { - const char* t = parse_expression(t1, last, db); - if (t != t1) - { - if (db.names.empty()) - return first; - num = db.names.back().move_full(); - db.names.pop_back(); - t1 = t; - } - } - if (t1 != last && *t1 == '_' && ++t1 != last) - { - const char* t = parse_type(t1, last, db); - if (t != t1) - { - if (db.names.empty()) - return first; - db.names.back().first += " vector[" + num + "]"; - first = t; - } - } - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= P # pointer-to -// ::= R # reference-to -// ::= O # rvalue reference-to (C++0x) -// ::= C # complex pair (C 2000) -// ::= G # imaginary (C 2000) -// ::= Dp # pack expansion (C++0x) -// ::= U # vendor extended type qualifier -// extension := U # objc-type -// extension := # starts with Dv - -// ::= objcproto # k0 = 9 + + k1 -// := # PU<11+>objcproto 11objc_object 11objc_object -> id - -template -const char* -parse_type(const char* first, const char* last, C& db) -{ - if (first != last) - { - switch (*first) - { - case 'r': - case 'V': - case 'K': - { - unsigned cv = 0; - const char* t = parse_cv_qualifiers(first, last, cv); - if (t != first) - { - bool is_function = *t == 'F'; - size_t k0 = db.names.size(); - const char* t1 = parse_type(t, last, db); - size_t k1 = db.names.size(); - if (t1 != t) - { - if (is_function) - db.subs.pop_back(); - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (is_function) - { - size_t p = db.names[k].second.size(); - if (db.names[k].second[p-2] == '&') - p -= 3; - else if (db.names[k].second.back() == '&') - p -= 2; - if (cv & 1) - { - db.names[k].second.insert(p, " const"); - p += 6; - } - if (cv & 2) - { - db.names[k].second.insert(p, " volatile"); - p += 9; - } - if (cv & 4) - db.names[k].second.insert(p, " restrict"); - } - else - { - if (cv & 1) - db.names[k].first.append(" const"); - if (cv & 2) - db.names[k].first.append(" volatile"); - if (cv & 4) - db.names[k].first.append(" restrict"); - } - db.subs.back().push_back(db.names[k]); - } - first = t1; - } - } - } - break; - default: - { - const char* t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - switch (*first) - { - case 'A': - t = parse_array_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'C': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.names.empty()) - return first; - db.names.back().first.append(" complex"); - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'F': - t = parse_function_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'G': - t = parse_type(first+1, last, db); - if (t != first+1) - { - if (db.names.empty()) - return first; - db.names.back().first.append(" imaginary"); - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'M': - t = parse_pointer_to_member_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - first = t; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - } - break; - case 'O': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&&"); - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'P': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") - { - db.names[k].first.append("*"); - } - else - { - db.names[k].first.replace(0, 11, "id"); - } - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'R': - { - size_t k0 = db.names.size(); - t = parse_type(first+1, last, db); - size_t k1 = db.names.size(); - if (t != first+1) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - { - if (db.names[k].second.substr(0, 2) == " [") - { - db.names[k].first += " ("; - db.names[k].second.insert(0, ")"); - } - else if (!db.names[k].second.empty() && - db.names[k].second.front() == '(') - { - db.names[k].first += "("; - db.names[k].second.insert(0, ")"); - } - db.names[k].first.append("&"); - db.subs.back().push_back(db.names[k]); - } - first = t; - } - break; - } - case 'T': - { - size_t k0 = db.names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.names.size(); - if (t != first) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - if (db.try_to_parse_template_args && k1 == k0+1) - { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) - { - auto args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += std::move(args); - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - t = t1; - } - } - first = t; - } - break; - } - case 'U': - if (first+1 != last) - { - t = parse_source_name(first+1, last, db); - if (t != first+1) - { - const char* t2 = parse_type(t, last, db); - if (t2 != t) - { - if (db.names.size() < 2) - return first; - auto type = db.names.back().move_full(); - db.names.pop_back(); - if (db.names.back().first.substr(0, 9) != "objcproto") - { - db.names.back() = type + " " + db.names.back().move_full(); - } - else - { - auto proto = db.names.back().move_full(); - db.names.pop_back(); - t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); - if (t != proto.data() + 9) - { - db.names.back() = type + "<" + db.names.back().move_full() + ">"; - } - else - { - db.names.push_back(type + " " + proto); - } - } - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t2; - } - } - } - break; - case 'S': - if (first+1 != last && first[1] == 't') - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - else - { - t = parse_substitution(first, last, db); - if (t != first) - { - first = t; - // Parsed a substitution. If the substitution is a - // it might be followed by . - t = parse_template_args(first, last, db); - if (t != first) - { - if (db.names.size() < 2) - return first; - auto template_args = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first += template_args; - // Need to create substitution for - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - } - break; - case 'D': - if (first+1 != last) - { - switch (first[1]) - { - case 'p': - { - size_t k0 = db.names.size(); - t = parse_type(first+2, last, db); - size_t k1 = db.names.size(); - if (t != first+2) - { - db.subs.emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.subs.back().push_back(db.names[k]); - first = t; - return first; - } - break; - } - case 't': - case 'T': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - return first; - } - break; - case 'v': - t = parse_vector_type(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - return first; - } - break; - } - } - // drop through - default: - // must check for builtin-types before class-enum-types to avoid - // ambiguities with operator-names - t = parse_builtin_type(first, last, db); - if (t != first) - { - first = t; - } - else - { - t = parse_name(first, last, db); - if (t != first) - { - if (db.names.empty()) - return first; - db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); - first = t; - } - } - break; - } - } - break; - } - } - } - return first; -} - -// -// ::= 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 # >>= -// ::= v # vendor extended operator - -template -const char* -parse_operator_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - switch (first[0]) - { - case 'a': - switch (first[1]) - { - case 'a': - db.names.push_back("operator&&"); - first += 2; - break; - case 'd': - case 'n': - db.names.push_back("operator&"); - first += 2; - break; - case 'N': - db.names.push_back("operator&="); - first += 2; - break; - case 'S': - db.names.push_back("operator="); - first += 2; - break; - } - break; - case 'c': - switch (first[1]) - { - case 'l': - db.names.push_back("operator()"); - first += 2; - break; - case 'm': - db.names.push_back("operator,"); - first += 2; - break; - case 'o': - db.names.push_back("operator~"); - first += 2; - break; - case 'v': - { - bool try_to_parse_template_args = db.try_to_parse_template_args; - db.try_to_parse_template_args = false; - const char* t = parse_type(first+2, last, db); - db.try_to_parse_template_args = try_to_parse_template_args; - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator "); - db.parsed_ctor_dtor_cv = true; - first = t; - } - } - break; - } - break; - case 'd': - switch (first[1]) - { - case 'a': - db.names.push_back("operator delete[]"); - first += 2; - break; - case 'e': - db.names.push_back("operator*"); - first += 2; - break; - case 'l': - db.names.push_back("operator delete"); - first += 2; - break; - case 'v': - db.names.push_back("operator/"); - first += 2; - break; - case 'V': - db.names.push_back("operator/="); - first += 2; - break; - } - break; - case 'e': - switch (first[1]) - { - case 'o': - db.names.push_back("operator^"); - first += 2; - break; - case 'O': - db.names.push_back("operator^="); - first += 2; - break; - case 'q': - db.names.push_back("operator=="); - first += 2; - break; - } - break; - case 'g': - switch (first[1]) - { - case 'e': - db.names.push_back("operator>="); - first += 2; - break; - case 't': - db.names.push_back("operator>"); - first += 2; - break; - } - break; - case 'i': - if (first[1] == 'x') - { - db.names.push_back("operator[]"); - first += 2; - } - break; - case 'l': - switch (first[1]) - { - case 'e': - db.names.push_back("operator<="); - first += 2; - break; - case 'i': - { - const char* t = parse_source_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator\"\" "); - first = t; - } - } - break; - case 's': - db.names.push_back("operator<<"); - first += 2; - break; - case 'S': - db.names.push_back("operator<<="); - first += 2; - break; - case 't': - db.names.push_back("operator<"); - first += 2; - break; - } - break; - case 'm': - switch (first[1]) - { - case 'i': - db.names.push_back("operator-"); - first += 2; - break; - case 'I': - db.names.push_back("operator-="); - first += 2; - break; - case 'l': - db.names.push_back("operator*"); - first += 2; - break; - case 'L': - db.names.push_back("operator*="); - first += 2; - break; - case 'm': - db.names.push_back("operator--"); - first += 2; - break; - } - break; - case 'n': - switch (first[1]) - { - case 'a': - db.names.push_back("operator new[]"); - first += 2; - break; - case 'e': - db.names.push_back("operator!="); - first += 2; - break; - case 'g': - db.names.push_back("operator-"); - first += 2; - break; - case 't': - db.names.push_back("operator!"); - first += 2; - break; - case 'w': - db.names.push_back("operator new"); - first += 2; - break; - } - break; - case 'o': - switch (first[1]) - { - case 'o': - db.names.push_back("operator||"); - first += 2; - break; - case 'r': - db.names.push_back("operator|"); - first += 2; - break; - case 'R': - db.names.push_back("operator|="); - first += 2; - break; - } - break; - case 'p': - switch (first[1]) - { - case 'm': - db.names.push_back("operator->*"); - first += 2; - break; - case 'l': - db.names.push_back("operator+"); - first += 2; - break; - case 'L': - db.names.push_back("operator+="); - first += 2; - break; - case 'p': - db.names.push_back("operator++"); - first += 2; - break; - case 's': - db.names.push_back("operator+"); - first += 2; - break; - case 't': - db.names.push_back("operator->"); - first += 2; - break; - } - break; - case 'q': - if (first[1] == 'u') - { - db.names.push_back("operator?"); - first += 2; - } - break; - case 'r': - switch (first[1]) - { - case 'm': - db.names.push_back("operator%"); - first += 2; - break; - case 'M': - db.names.push_back("operator%="); - first += 2; - break; - case 's': - db.names.push_back("operator>>"); - first += 2; - break; - case 'S': - db.names.push_back("operator>>="); - first += 2; - break; - } - break; - case 'v': - if (std::isdigit(first[1])) - { - const char* t = parse_source_name(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "operator "); - first = t; - } - } - break; - } - } - return first; -} - -template -const char* -parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) -{ - const char* t = parse_number(first, last); - if (t != first && t != last && *t == 'E') - { - if (lit.size() > 3) - db.names.push_back("(" + lit + ")"); - else - db.names.emplace_back(); - if (*first == 'n') - { - db.names.back().first += '-'; - ++first; - } - db.names.back().first.append(first, t); - if (lit.size() <= 3) - db.names.back().first += lit; - first = t+1; - } - return first; -} - -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// ::= L _ E # complex floating point literal (C 2000) -// ::= L E # external name - -template -const char* -parse_expr_primary(const char* first, const char* last, C& db) -{ - if (last - first >= 4 && *first == 'L') - { - switch (first[1]) - { - case 'w': - { - const char* t = parse_integer_literal(first+2, last, "wchar_t", db); - if (t != first+2) - first = t; - } - break; - case 'b': - if (first[3] == 'E') - { - switch (first[2]) - { - case '0': - db.names.push_back("false"); - first += 4; - break; - case '1': - db.names.push_back("true"); - first += 4; - break; - } - } - break; - case 'c': - { - const char* t = parse_integer_literal(first+2, last, "char", db); - if (t != first+2) - first = t; - } - break; - case 'a': - { - const char* t = parse_integer_literal(first+2, last, "signed char", db); - if (t != first+2) - first = t; - } - break; - case 'h': - { - const char* t = parse_integer_literal(first+2, last, "unsigned char", db); - if (t != first+2) - first = t; - } - break; - case 's': - { - const char* t = parse_integer_literal(first+2, last, "short", db); - if (t != first+2) - first = t; - } - break; - case 't': - { - const char* t = parse_integer_literal(first+2, last, "unsigned short", db); - if (t != first+2) - first = t; - } - break; - case 'i': - { - const char* t = parse_integer_literal(first+2, last, "", db); - if (t != first+2) - first = t; - } - break; - case 'j': - { - const char* t = parse_integer_literal(first+2, last, "u", db); - if (t != first+2) - first = t; - } - break; - case 'l': - { - const char* t = parse_integer_literal(first+2, last, "l", db); - if (t != first+2) - first = t; - } - break; - case 'm': - { - const char* t = parse_integer_literal(first+2, last, "ul", db); - if (t != first+2) - first = t; - } - break; - case 'x': - { - const char* t = parse_integer_literal(first+2, last, "ll", db); - if (t != first+2) - first = t; - } - break; - case 'y': - { - const char* t = parse_integer_literal(first+2, last, "ull", db); - if (t != first+2) - first = t; - } - break; - case 'n': - { - const char* t = parse_integer_literal(first+2, last, "__int128", db); - if (t != first+2) - first = t; - } - break; - case 'o': - { - const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); - if (t != first+2) - first = t; - } - break; - case 'f': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'd': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'e': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case '_': - if (first[2] == 'Z') - { - const char* t = parse_encoding(first+3, last, db); - if (t != first+3 && t != last && *t == 'E') - first = t+1; - } - break; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - break; - default: - { - // might be named type - const char* t = parse_type(first+1, last, db); - if (t != first+1 && t != last) - { - if (*t != 'E') - { - const char* n = t; - for (; n != last && isdigit(*n); ++n) - ; - if (n != t && n != last && *n == 'E') - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); - first = n+1; - break; - } - } - else - { - first = t+1; - break; - } - } - } - } - } - return first; -} - -template -String -base_name(String& s) -{ - if (s.empty()) - return s; - if (s == "std::string") - { - s = "std::basic_string, std::allocator >"; - return "basic_string"; - } - if (s == "std::istream") - { - s = "std::basic_istream >"; - return "basic_istream"; - } - if (s == "std::ostream") - { - s = "std::basic_ostream >"; - return "basic_ostream"; - } - if (s == "std::iostream") - { - s = "std::basic_iostream >"; - return "basic_iostream"; - } - const char* const pf = s.data(); - const char* pe = pf + s.size(); - if (pe[-1] == '>') - { - unsigned c = 1; - while (true) - { - if (--pe == pf) - return String(); - if (pe[-1] == '<') - { - if (--c == 0) - { - --pe; - break; - } - } - else if (pe[-1] == '>') - ++c; - } - } - const char* p0 = pe - 1; - for (; p0 != pf; --p0) - { - if (*p0 == ':') - { - ++p0; - break; - } - } - return String(p0, pe); -} - -// ::= 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 # ? - -template -const char* -parse_ctor_dtor_name(const char* first, const char* last, C& db) -{ - if (last-first >= 2 && !db.names.empty()) - { - switch (first[0]) - { - case 'C': - switch (first[1]) - { - case '1': - case '2': - case '3': - case '5': - if (db.names.empty()) - return first; - db.names.push_back(base_name(db.names.back().first)); - first += 2; - db.parsed_ctor_dtor_cv = true; - break; - } - break; - case 'D': - switch (first[1]) - { - case '0': - case '1': - case '2': - case '5': - if (db.names.empty()) - return first; - db.names.push_back("~" + base_name(db.names.back().first)); - first += 2; - db.parsed_ctor_dtor_cv = true; - break; - } - break; - } - } - return first; -} - -// ::= Ut [ ] _ -// ::= -// -// ::= Ul E [ ] _ -// -// ::= + # Parameter types or "v" if the lambda has no parameters - -template -const char* -parse_unnamed_type_name(const char* first, const char* last, C& db) -{ - if (last - first > 2 && first[0] == 'U') - { - char type = first[1]; - switch (type) - { - case 't': - { - db.names.push_back(typename C::String("'unnamed")); - const char* t0 = first+2; - if (t0 == last) - { - db.names.pop_back(); - return first; - } - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - db.names.back().first.append(t0, t1); - t0 = t1; - } - db.names.back().first.push_back('\''); - if (t0 == last || *t0 != '_') - { - db.names.pop_back(); - return first; - } - first = t0 + 1; - } - break; - case 'l': - { - db.names.push_back(typename C::String("'lambda'(")); - const char* t0 = first+2; - if (first[2] == 'v') - { - db.names.back().first += ')'; - ++t0; - } - else - { - const char* t1 = parse_type(t0, last, db); - if (t1 == t0) - { - db.names.pop_back(); - return first; - } - if (db.names.size() < 2) - return first; - auto tmp = db.names.back().move_full(); - db.names.pop_back(); - db.names.back().first.append(tmp); - t0 = t1; - while (true) - { - t1 = parse_type(t0, last, db); - if (t1 == t0) - break; - if (db.names.size() < 2) - return first; - tmp = db.names.back().move_full(); - db.names.pop_back(); - if (!tmp.empty()) - { - db.names.back().first.append(", "); - db.names.back().first.append(tmp); - } - t0 = t1; - } - db.names.back().first.append(")"); - } - if (t0 == last || *t0 != 'E') - { - db.names.pop_back(); - return first; - } - ++t0; - if (t0 == last) - { - db.names.pop_back(); - return first; - } - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); - t0 = t1; - } - if (t0 == last || *t0 != '_') - { - db.names.pop_back(); - return first; - } - first = t0 + 1; - } - break; - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= - -template -const char* -parse_unqualified_name(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t; - switch (*first) - { - case 'C': - case 'D': - t = parse_ctor_dtor_name(first, last, db); - if (t != first) - first = t; - break; - case 'U': - t = parse_unnamed_type_name(first, last, db); - if (t != first) - first = t; - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - t = parse_source_name(first, last, db); - if (t != first) - first = t; - break; - default: - t = parse_operator_name(first, last, db); - if (t != first) - first = t; - break; - }; - } - return first; -} - -// ::= -// ::= St # ::std:: -// extension ::= StL - -template -const char* -parse_unscoped_name(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - const char* t0 = first; - bool St = false; - if (first[0] == 'S' && first[1] == 't') - { - t0 += 2; - St = true; - if (t0 != last && *t0 == 'L') - ++t0; - } - const char* t1 = parse_unqualified_name(t0, last, db); - if (t1 != t0) - { - if (St) - { - if (db.names.empty()) - return first; - db.names.back().first.insert(0, "std::"); - } - first = t1; - } - } - return first; -} - -// at # alignof (a type) - -template -const char* -parse_alignof_type(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -// az # alignof (a expression) - -template -const char* -parse_alignof_expr(const char* first, const char* last, C& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.names.empty()) - return first; - db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; - first = t; - } - } - return first; -} - -template -const char* -parse_noexcept_expression(const char* first, const char* last, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.names.empty()) - return first; - db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; - first = t1; - } - return first; -} - -template -const char* -parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.names.empty()) - return first; - db.names.back().first = op + "(" + db.names.back().move_full() + ")"; - first = t1; - } - return first; -} - -template -const char* -parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.names.size() < 2) - return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - auto& nm = db.names.back().first; - nm.clear(); - if (op == ">") - nm += '('; - nm += "(" + op1 + ") " + op + " (" + op2 + ")"; - if (op == ">") - nm += ')'; - first = t2; - } - else - db.names.pop_back(); - } - return first; -} - -// ::= -// ::= -// ::= -// ::= cl + E # call -// ::= cv # conversion with one argument -// ::= cv _ * E # conversion with a different number of arguments -// ::= [gs] nw * _ E # new (expr-list) type -// ::= [gs] nw * _ # new (expr-list) type (init) -// ::= [gs] na * _ E # new[] (expr-list) type -// ::= [gs] na * _ # new[] (expr-list) type (init) -// ::= [gs] dl # delete expression -// ::= [gs] da # delete[] expression -// ::= pp_ # prefix ++ -// ::= mm_ # prefix -- -// ::= ti # typeid (type) -// ::= te # typeid (expression) -// ::= dc # dynamic_cast (expression) -// ::= sc # static_cast (expression) -// ::= cc # const_cast (expression) -// ::= rc # reinterpret_cast (expression) -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= nx # noexcept (expression) -// ::= -// ::= -// ::= dt # expr.name -// ::= pt # expr->name -// ::= ds # expr.*expr -// ::= sZ # size of a parameter pack -// ::= sZ # size of a function parameter pack -// ::= sp # pack expansion -// ::= tw # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= - -template -const char* -parse_expression(const char* first, const char* last, C& db) -{ - if (last - first >= 2) - { - const char* t = first; - bool parsed_gs = false; - if (last - first >= 4 && t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - switch (*t) - { - case 'L': - first = parse_expr_primary(first, last, db); - break; - case 'T': - first = parse_template_param(first, last, db); - break; - case 'f': - first = parse_function_param(first, last, db); - break; - case 'a': - switch (t[1]) - { - case 'a': - t = parse_binary_expression(first+2, last, "&&", db); - if (t != first+2) - first = t; - break; - case 'd': - t = parse_prefix_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'n': - t = parse_binary_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'N': - t = parse_binary_expression(first+2, last, "&=", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "=", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_alignof_type(first, last, db); - break; - case 'z': - first = parse_alignof_expr(first, last, db); - break; - } - break; - case 'c': - switch (t[1]) - { - case 'c': - first = parse_const_cast_expr(first, last, db); - break; - case 'l': - first = parse_call_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, ",", db); - if (t != first+2) - first = t; - break; - case 'o': - t = parse_prefix_expression(first+2, last, "~", db); - if (t != first+2) - first = t; - break; - case 'v': - first = parse_conversion_expr(first, last, db); - break; - } - break; - case 'd': - switch (t[1]) - { - case 'a': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.names.empty()) - return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete[] " + db.names.back().move_full(); - first = t1; - } - } - break; - case 'c': - first = parse_dynamic_cast_expr(first, last, db); - break; - case 'e': - t = parse_prefix_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'l': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.names.empty()) - return first; - db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + - "delete " + db.names.back().move_full(); - first = t1; - } - } - break; - case 'n': - return parse_unresolved_name(first, last, db); - case 's': - first = parse_dot_star_expr(first, last, db); - break; - case 't': - first = parse_dot_expr(first, last, db); - break; - case 'v': - t = parse_binary_expression(first+2, last, "/", db); - if (t != first+2) - first = t; - break; - case 'V': - t = parse_binary_expression(first+2, last, "/=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'e': - switch (t[1]) - { - case 'o': - t = parse_binary_expression(first+2, last, "^", db); - if (t != first+2) - first = t; - break; - case 'O': - t = parse_binary_expression(first+2, last, "^=", db); - if (t != first+2) - first = t; - break; - case 'q': - t = parse_binary_expression(first+2, last, "==", db); - if (t != first+2) - first = t; - break; - } - break; - case 'g': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, ">=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, ">", db); - if (t != first+2) - first = t; - break; - } - break; - case 'i': - if (t[1] == 'x') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.names.size() < 2) - return first; - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ")[" + op2 + "]"; - first = t2; - } - else - db.names.pop_back(); - } - } - break; - case 'l': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, "<=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, "<<", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "<<=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, "<", db); - if (t != first+2) - first = t; - break; - } - break; - case 'm': - switch (t[1]) - { - case 'i': - t = parse_binary_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 'I': - t = parse_binary_expression(first+2, last, "-=", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "*=", db); - if (t != first+2) - first = t; - break; - case 'm': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "--", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")--"; - first = t1; - } - } - break; - } - break; - case 'n': - switch (t[1]) - { - case 'a': - case 'w': - first = parse_new_expr(first, last, db); - break; - case 'e': - t = parse_binary_expression(first+2, last, "!=", db); - if (t != first+2) - first = t; - break; - case 'g': - t = parse_prefix_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_prefix_expression(first+2, last, "!", db); - if (t != first+2) - first = t; - break; - case 'x': - t = parse_noexcept_expression(first+2, last, db); - if (t != first+2) - first = t; - break; - } - break; - case 'o': - switch (t[1]) - { - case 'n': - return parse_unresolved_name(first, last, db); - case 'o': - t = parse_binary_expression(first+2, last, "||", db); - if (t != first+2) - first = t; - break; - case 'r': - t = parse_binary_expression(first+2, last, "|", db); - if (t != first+2) - first = t; - break; - case 'R': - t = parse_binary_expression(first+2, last, "|=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'p': - switch (t[1]) - { - case 'm': - t = parse_binary_expression(first+2, last, "->*", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "+=", db); - if (t != first+2) - first = t; - break; - case 'p': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "++", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.names.empty()) - return first; - db.names.back() = "(" + db.names.back().move_full() + ")++"; - first = t1; - } - } - break; - case 's': - t = parse_prefix_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_arrow_expr(first, last, db); - break; - } - break; - case 'q': - if (t[1] == 'u') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - const char* t3 = parse_expression(t2, last, db); - if (t3 != t2) - { - if (db.names.size() < 3) - return first; - auto op3 = db.names.back().move_full(); - db.names.pop_back(); - auto op2 = db.names.back().move_full(); - db.names.pop_back(); - auto op1 = db.names.back().move_full(); - db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; - first = t3; - } - else - { - db.names.pop_back(); - db.names.pop_back(); - } - } - else - db.names.pop_back(); - } - } - break; - case 'r': - switch (t[1]) - { - case 'c': - first = parse_reinterpret_cast_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, "%", db); - if (t != first+2) - first = t; - break; - case 'M': - t = parse_binary_expression(first+2, last, "%=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, ">>", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, ">>=", db); - if (t != first+2) - first = t; - break; - } - break; - case 's': - switch (t[1]) - { - case 'c': - first = parse_static_cast_expr(first, last, db); - break; - case 'p': - first = parse_pack_expansion(first, last, db); - break; - case 'r': - return parse_unresolved_name(first, last, db); - case 't': - first = parse_sizeof_type_expr(first, last, db); - break; - case 'z': - first = parse_sizeof_expr_expr(first, last, db); - break; - case 'Z': - if (last - t >= 3) - { - switch (t[2]) - { - case 'T': - first = parse_sizeof_param_pack_expr(first, last, db); - break; - case 'f': - first = parse_sizeof_function_param_pack_expr(first, last, db); - break; - } - } - break; - } - break; - case 't': - switch (t[1]) - { - case 'e': - case 'i': - first = parse_typeid_expr(first, last, db); - break; - case 'r': - db.names.push_back("throw"); - first += 2; - break; - case 'w': - first = parse_throw_expr(first, last, db); - break; - } - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return parse_unresolved_name(first, last, db); - } - } - return first; -} - -// ::= # type or template -// ::= X E # expression -// ::= # simple expressions -// ::= J * E # argument pack -// ::= LZ E # extension - -template -const char* -parse_template_arg(const char* first, const char* last, C& db) -{ - if (first != last) - { - const char* t; - switch (*first) - { - case 'X': - t = parse_expression(first+1, last, db); - if (t != first+1) - { - if (t != last && *t == 'E') - first = t+1; - } - break; - case 'J': - t = first+1; - if (t == last) - return first; - while (*t != 'E') - { - const char* t1 = parse_template_arg(t, last, db); - if (t1 == t) - return first; - t = t1; - } - first = t+1; - break; - case 'L': - // or LZ E - if (first+1 != last && first[1] == 'Z') - { - t = parse_encoding(first+2, last, db); - if (t != first+2 && t != last && *t == 'E') - first = t+1; - } - else - first = parse_expr_primary(first, last, db); - break; - default: - // - first = parse_type(first, last, db); - break; - } - } - return first; -} - -// ::= I * E -// extension, the abi says + - -template -const char* -parse_template_args(const char* first, const char* last, C& db) -{ - if (last - first >= 2 && *first == 'I') - { - if (db.tag_templates) - db.template_param.back().clear(); - const char* t = first+1; - typename C::String args("<"); - while (*t != 'E') - { - if (db.tag_templates) - db.template_param.emplace_back(db.names.get_allocator()); - size_t k0 = db.names.size(); - const char* t1 = parse_template_arg(t, last, db); - size_t k1 = db.names.size(); - if (db.tag_templates) - db.template_param.pop_back(); - if (t1 == t || t1 == last) - return first; - if (db.tag_templates) - { - db.template_param.back().emplace_back(db.names.get_allocator()); - for (size_t k = k0; k < k1; ++k) - db.template_param.back().back().push_back(db.names[k]); - } - for (size_t k = k0; k < k1; ++k) - { - if (args.size() > 1) - args += ", "; - args += db.names[k].move_full(); - } - for (; k1 != k0; --k1) - db.names.pop_back(); - t = t1; - } - first = t + 1; - if (args.back() != '>') - args += ">"; - else - args += " >"; - db.names.push_back(std::move(args)); - - } - return first; -} - -// ::= N [] [] E -// ::= N [] [] E -// -// ::= -// ::= -// ::= -// ::= -// ::= # empty -// ::= -// ::= -// extension ::= L -// -// ::=