diff options
author | 2021-01-11 15:31:56 +0000 | |
---|---|---|
committer | 2021-01-11 15:31:56 +0000 | |
commit | 16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef (patch) | |
tree | 1a7dd8152b94f6f8cd318bfaf85aa40882854583 /lib/libcxxabi/src | |
parent | sync (diff) | |
download | wireguard-openbsd-16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef.tar.xz wireguard-openbsd-16ff81ed8b1ed9aa06fb1a731a2446b66cc49bef.zip |
Remove libc++ and libc++abi 8.0.0 now that we switched to version 10.0.1
in the gnu/ directory.
Diffstat (limited to 'lib/libcxxabi/src')
32 files changed, 0 insertions, 12332 deletions
diff --git a/lib/libcxxabi/src/CMakeLists.txt b/lib/libcxxabi/src/CMakeLists.txt deleted file mode 100644 index 7e21fb2d792..00000000000 --- a/lib/libcxxabi/src/CMakeLists.txt +++ /dev/null @@ -1,243 +0,0 @@ -# Get sources -set(LIBCXXABI_SOURCES - # C++ABI files - cxa_aux_runtime.cpp - cxa_default_handlers.cpp - cxa_demangle.cpp - cxa_exception_storage.cpp - cxa_guard.cpp - cxa_handlers.cpp - cxa_unexpected.cpp - cxa_vector.cpp - cxa_virtual.cpp - # C++ STL files - stdlib_exception.cpp - stdlib_stdexcept.cpp - stdlib_typeinfo.cpp - # Internal files - abort_message.cpp - fallback_malloc.cpp - private_typeinfo.cpp -) - -if (LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS) - list(APPEND LIBCXXABI_SOURCES stdlib_new_delete.cpp) -endif() - -if (LIBCXXABI_ENABLE_EXCEPTIONS) - list(APPEND LIBCXXABI_SOURCES cxa_exception.cpp) - list(APPEND LIBCXXABI_SOURCES cxa_personality.cpp) -else() - list(APPEND LIBCXXABI_SOURCES cxa_noexception.cpp) -endif() - -if (LIBCXXABI_ENABLE_THREADS AND (UNIX OR FUCHSIA) AND NOT (APPLE OR CYGWIN)) - list(APPEND LIBCXXABI_SOURCES cxa_thread_atexit.cpp) -endif() - -set(LIBCXXABI_HEADERS ../include/cxxabi.h) - -# Add all the headers to the project for IDEs. -if (MSVC_IDE OR XCODE) - # Force them all into the headers dir on MSVC, otherwise they end up at - # project scope because they don't have extensions. - if (MSVC_IDE) - source_group("Header Files" FILES ${LIBCXXABI_HEADERS}) - endif() -endif() - -include_directories("${LIBCXXABI_LIBCXX_INCLUDES}") - -if (LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL) - add_definitions(-DHAVE___CXA_THREAD_ATEXIT_IMPL) -endif() - -if (LIBCXXABI_ENABLE_THREADS) - add_library_flags_if(LIBCXXABI_HAS_PTHREAD_LIB pthread) -endif() - -add_library_flags_if(LIBCXXABI_HAS_C_LIB c) -if (LIBCXXABI_USE_LLVM_UNWINDER) - # Prefer using the in-tree version of libunwind, either shared or static. If - # none are found fall back to using -lunwind. - # FIXME: Is it correct to prefer the static version of libunwind? - if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_static) - else() - list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind) - endif() - if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind_shared) - elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - # We handle this by directly merging libunwind objects into libc++abi. - else() - list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind) - endif() -else() - add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s) -endif() -if (MINGW) - # MINGW_LIBRARIES is defined in config-ix.cmake - list(APPEND LIBCXXABI_LIBRARIES ${MINGW_LIBRARIES}) -endif() - -# Setup flags. -add_link_flags_if_supported(-nodefaultlibs) - -set(LIBCXXABI_SHARED_LINK_FLAGS) - -if ( APPLE ) - if ( CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6" ) - list(APPEND LIBCXXABI_COMPILE_FLAGS "-U__STRICT_ANSI__") - list(APPEND LIBCXXABI_SHARED_LINK_FLAGS - "-compatibility_version 1" - "-current_version 1" - "-install_name /usr/lib/libc++abi.1.dylib") - list(APPEND LIBCXXABI_LINK_FLAGS - "/usr/lib/libSystem.B.dylib") - else() - list(APPEND LIBCXXABI_SHARED_LINK_FLAGS - "-compatibility_version 1" - "-install_name /usr/lib/libc++abi.1.dylib") - endif() - - if (LLVM_USE_SANITIZER) - if (("${LLVM_USE_SANITIZER}" STREQUAL "Address") OR - ("${LLVM_USE_SANITIZER}" STREQUAL "Address;Undefined") OR - ("${LLVM_USE_SANITIZER}" STREQUAL "Undefined;Address")) - set(LIBFILE "libclang_rt.asan_osx_dynamic.dylib") - elseif("${LLVM_USE_SANITIZER}" STREQUAL "Undefined") - set(LIBFILE "libclang_rt.ubsan_osx_dynamic.dylib") - elseif("${LLVM_USE_SANITIZER}" STREQUAL "Thread") - set(LIBFILE "libclang_rt.tsan_osx_dynamic.dylib") - else() - message(WARNING "LLVM_USE_SANITIZER=${LLVM_USE_SANITIZER} is not supported on OS X") - endif() - if (LIBFILE) - find_compiler_rt_dir(LIBDIR) - if (NOT IS_DIRECTORY "${LIBDIR}") - message(FATAL_ERROR "Cannot find compiler-rt directory on OS X required for LLVM_USE_SANITIZER") - endif() - set(LIBCXXABI_SANITIZER_LIBRARY "${LIBDIR}/${LIBFILE}") - set(LIBCXXABI_SANITIZER_LIBRARY "${LIBCXXABI_SANITIZER_LIBRARY}" PARENT_SCOPE) - message(STATUS "Manually linking compiler-rt library: ${LIBCXXABI_SANITIZER_LIBRARY}") - add_library_flags("${LIBCXXABI_SANITIZER_LIBRARY}") - add_link_flags("-Wl,-rpath,${LIBDIR}") - endif() - endif() -endif() - -split_list(LIBCXXABI_COMPILE_FLAGS) -split_list(LIBCXXABI_LINK_FLAGS) -split_list(LIBCXXABI_SHARED_LINK_FLAGS) - -# FIXME: libc++abi.so will not link when modules are enabled because it depends -# on symbols defined in libc++.so which has not yet been built. -if (LLVM_ENABLE_MODULES) - string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") -endif() - -# Add a object library that contains the compiled source files. -add_library(cxxabi_objects OBJECT ${LIBCXXABI_SOURCES} ${LIBCXXABI_HEADERS}) -set_target_properties(cxxabi_objects - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - COMPILE_FLAGS - "${LIBCXXABI_COMPILE_FLAGS}" - POSITION_INDEPENDENT_CODE - ON) - -# Build the shared library. -if (LIBCXXABI_ENABLE_SHARED) - add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>) - if(COMMAND llvm_setup_rpath) - llvm_setup_rpath(cxxabi_shared) - endif() - target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_SHARED_LIBRARIES}) - set_target_properties(cxxabi_shared - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - LINK_FLAGS - "${LIBCXXABI_LINK_FLAGS} ${LIBCXXABI_SHARED_LINK_FLAGS}" - OUTPUT_NAME - "c++abi" - POSITION_INDEPENDENT_CODE - ON - SOVERSION - "1" - VERSION - "1.0") - list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_shared") - if (LIBCXXABI_INSTALL_SHARED_LIBRARY) - list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared") - endif() -endif() - -# Build the static library. -if (LIBCXXABI_ENABLE_STATIC) - set(cxxabi_static_sources $<TARGET_OBJECTS:cxxabi_objects>) - if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY) - if (TARGET unwind_static OR HAVE_LIBUNWIND) - list(APPEND cxxabi_static_sources $<TARGET_OBJECTS:unwind_objects>) - endif() - endif() - add_library(cxxabi_static STATIC ${cxxabi_static_sources}) - target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_STATIC_LIBRARIES}) - set_target_properties(cxxabi_static - PROPERTIES - CXX_EXTENSIONS - OFF - CXX_STANDARD - 11 - CXX_STANDARD_REQUIRED - ON - LINK_FLAGS - "${LIBCXXABI_LINK_FLAGS}" - OUTPUT_NAME - "c++abi" - POSITION_INDEPENDENT_CODE - ON) - list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_static") - if (LIBCXXABI_INSTALL_STATIC_LIBRARY) - list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_static") - endif() -endif() - -# Add a meta-target for both libraries. -add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS}) - -if (LIBCXXABI_INSTALL_LIBRARY) - install(TARGETS ${LIBCXXABI_INSTALL_TARGETS} - LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi - ) -endif() - -if (NOT CMAKE_CONFIGURATION_TYPES AND LIBCXXABI_INSTALL_LIBRARY) - add_custom_target(install-cxxabi - DEPENDS cxxabi - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=cxxabi - -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") - add_custom_target(install-cxxabi-stripped - DEPENDS cxxabi - COMMAND "${CMAKE_COMMAND}" - -DCMAKE_INSTALL_COMPONENT=cxxabi - -DCMAKE_INSTALL_DO_STRIP=1 - -P "${LIBCXXABI_BINARY_DIR}/cmake_install.cmake") - - # TODO: This is a legacy target name and should be removed at some point. - add_custom_target(install-libcxxabi DEPENDS install-cxxabi) -endif() diff --git a/lib/libcxxabi/src/abort_message.cpp b/lib/libcxxabi/src/abort_message.cpp deleted file mode 100644 index 7a2a9f835bd..00000000000 --- a/lib/libcxxabi/src/abort_message.cpp +++ /dev/null @@ -1,78 +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 <stdlib.h> -#include <stdio.h> -#include <stdarg.h> -#include "abort_message.h" - -#ifdef __BIONIC__ -#include <android/api-level.h> -#if __ANDROID_API__ >= 21 -#include <syslog.h> -extern "C" void android_set_abort_message(const char* msg); -#else -#include <assert.h> -#endif // __ANDROID_API__ >= 21 -#endif // __BIONIC__ - -#ifdef __APPLE__ -# if defined(__has_include) && __has_include(<CrashReporterClient.h>) -# define HAVE_CRASHREPORTERCLIENT_H -# include <CrashReporterClient.h> -# endif -#endif - -void abort_message(const char* format, ...) -{ - // write message to stderr -#if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) -#ifdef __APPLE__ - fprintf(stderr, "libc++abi.dylib: "); -#endif - va_list list; - va_start(list, format); - vfprintf(stderr, format, list); - va_end(list); - fprintf(stderr, "\n"); -#endif - -#if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H) - // record message in crash report - char* buffer; - va_list list2; - va_start(list2, format); - vasprintf(&buffer, format, list2); - va_end(list2); - CRSetCrashLogMessage(buffer); -#elif defined(__BIONIC__) - char* buffer; - va_list list2; - va_start(list2, format); - vasprintf(&buffer, format, list2); - va_end(list2); - -#if __ANDROID_API__ >= 21 - // Show error in tombstone. - android_set_abort_message(buffer); - - // Show error in logcat. - openlog("libc++abi", 0, 0); - syslog(LOG_CRIT, "%s", buffer); - closelog(); -#else - // The good error reporting wasn't available in Android until L. Since we're - // about to abort anyway, just call __assert2, which will log _somewhere_ - // (tombstone and/or logcat) in older releases. - __assert2(__FILE__, __LINE__, __func__, buffer); -#endif // __ANDROID_API__ >= 21 -#endif // __BIONIC__ - - abort(); -} diff --git a/lib/libcxxabi/src/abort_message.h b/lib/libcxxabi/src/abort_message.h deleted file mode 100644 index e8f9571cb56..00000000000 --- a/lib/libcxxabi/src/abort_message.h +++ /dev/null @@ -1,27 +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 "cxxabi.h" - -#ifdef __cplusplus -extern "C" { -#endif - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void -abort_message(const char *format, ...) __attribute__((format(printf, 1, 2))); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/lib/libcxxabi/src/cxa_aux_runtime.cpp b/lib/libcxxabi/src/cxa_aux_runtime.cpp deleted file mode 100644 index 878d3bd034d..00000000000 --- a/lib/libcxxabi/src/cxa_aux_runtime.cpp +++ /dev/null @@ -1,44 +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 <new> -#include <typeinfo> - -namespace __cxxabiv1 { -extern "C" { -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_cast(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_cast(); -#else - std::terminate(); -#endif -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_bad_typeid(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_typeid(); -#else - std::terminate(); -#endif -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void -__cxa_throw_bad_array_new_length(void) { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_array_new_length(); -#else - std::terminate(); -#endif -} -} // extern "C" -} // abi diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp deleted file mode 100644 index f00e95929b9..00000000000 --- a/lib/libcxxabi/src/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 <stdexcept> -#include <new> -#include <exception> -#include <cstdlib> -#include "abort_message.h" -#include "cxxabi.h" -#include "cxa_handlers.hpp" -#include "cxa_exception.hpp" -#include "private_typeinfo.h" -#include "include/atomic_support.h" - -#if !defined(LIBCXXABI_SILENT_TERMINATE) -static const char* cause = "uncaught"; - -__attribute__((noreturn)) -static void demangling_terminate_handler() -{ - // If there might be an uncaught exception - using namespace __cxxabiv1; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals) - { - __cxa_exception* exception_header = globals->caughtExceptions; - // If there is an uncaught exception - if (exception_header) - { - _Unwind_Exception* unwind_exception = - reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; - if (__isOurExceptionClass(unwind_exception)) - { - void* thrown_object = - __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)exception_header)->primaryException : - exception_header + 1; - const __shim_type_info* thrown_type = - static_cast<const __shim_type_info*>(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<const __shim_type_info*>(&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<const std::exception*>(thrown_object); - abort_message("terminating with %s exception of type %s: %s", - cause, name, e->what()); - } - else - // Else just note that we're terminating with an exception - abort_message("terminating with %s exception of type %s", - cause, name); - } - else - // Else we're terminating with a foreign exception - abort_message("terminating with %s foreign exception", cause); - } - } - // Else just note that we're terminating - abort_message("terminating"); -} - -__attribute__((noreturn)) -static void demangling_unexpected_handler() -{ - cause = "unexpected"; - std::terminate(); -} - -static std::terminate_handler default_terminate_handler = demangling_terminate_handler; -static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler; -#else -static std::terminate_handler default_terminate_handler = std::abort; -static std::terminate_handler default_unexpected_handler = std::terminate; -#endif - -// -// Global variables that hold the pointers to the current handler -// -_LIBCXXABI_DATA_VIS -std::terminate_handler __cxa_terminate_handler = default_terminate_handler; - -_LIBCXXABI_DATA_VIS -std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; - -namespace std -{ - -unexpected_handler -set_unexpected(unexpected_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_unexpected_handler; - return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func, - _AO_Acq_Rel); -} - -terminate_handler -set_terminate(terminate_handler func) _NOEXCEPT -{ - if (func == 0) - func = default_terminate_handler; - return __libcpp_atomic_exchange(&__cxa_terminate_handler, func, - _AO_Acq_Rel); -} - -} diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp deleted file mode 100644 index f227addbdae..00000000000 --- a/lib/libcxxabi/src/cxa_demangle.cpp +++ /dev/null @@ -1,370 +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. -// -//===----------------------------------------------------------------------===// - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - -#define _LIBCPP_NO_EXCEPTIONS - -#include "__cxxabi_config.h" - -#include "demangle/ItaniumDemangle.h" - -#include <cassert> -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <functional> -#include <numeric> -#include <utility> -#include <vector> - -using namespace itanium_demangle; - -constexpr const char *itanium_demangle::FloatData<float>::spec; -constexpr const char *itanium_demangle::FloatData<double>::spec; -constexpr const char *itanium_demangle::FloatData<long double>::spec; - -// <discriminator> := _ <non-negative number> # when number < 10 -// := __ <non-negative number> _ # when number >= 10 -// extension := decimal-digit+ # at the end of string -const char *itanium_demangle::parse_discriminator(const char *first, - const char *last) { - // parse but ignore discriminator - if (first != last) { - if (*first == '_') { - const char *t1 = first + 1; - if (t1 != last) { - if (std::isdigit(*t1)) - first = t1 + 1; - else if (*t1 == '_') { - for (++t1; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 != last && *t1 == '_') - first = t1 + 1; - } - } - } else if (std::isdigit(*first)) { - const char *t1 = first + 1; - for (; t1 != last && std::isdigit(*t1); ++t1) - ; - if (t1 == last) - first = last; - } - } - return first; -} - -#ifndef NDEBUG -namespace { -struct DumpVisitor { - unsigned Depth = 0; - bool PendingNewline = false; - - template<typename NodeT> static constexpr bool wantsNewline(const NodeT *) { - return true; - } - static bool wantsNewline(NodeArray A) { return !A.empty(); } - static constexpr bool wantsNewline(...) { return false; } - - template<typename ...Ts> static bool anyWantNewline(Ts ...Vs) { - for (bool B : {wantsNewline(Vs)...}) - if (B) - return true; - return false; - } - - void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); - } - void print(const Node *N) { - if (N) - N->visit(std::ref(*this)); - else - printStr("<null>"); - } - void print(NodeOrString NS) { - if (NS.isNode()) - print(NS.asNode()); - else if (NS.isString()) - print(NS.asString()); - else - printStr("NodeOrString()"); - } - void print(NodeArray A) { - ++Depth; - printStr("{"); - bool First = true; - for (const Node *N : A) { - if (First) - print(N); - else - printWithComma(N); - First = false; - } - printStr("}"); - --Depth; - } - - // Overload used when T is exactly 'bool', not merely convertible to 'bool'. - void print(bool B) { printStr(B ? "true" : "false"); } - - template <class T> - typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) { - fprintf(stderr, "%llu", (unsigned long long)N); - } - - template <class T> - typename std::enable_if<std::is_signed<T>::value>::type print(T N) { - fprintf(stderr, "%lld", (long long)N); - } - - void print(ReferenceKind RK) { - switch (RK) { - case ReferenceKind::LValue: - return printStr("ReferenceKind::LValue"); - case ReferenceKind::RValue: - return printStr("ReferenceKind::RValue"); - } - } - void print(FunctionRefQual RQ) { - switch (RQ) { - case FunctionRefQual::FrefQualNone: - return printStr("FunctionRefQual::FrefQualNone"); - case FunctionRefQual::FrefQualLValue: - return printStr("FunctionRefQual::FrefQualLValue"); - case FunctionRefQual::FrefQualRValue: - return printStr("FunctionRefQual::FrefQualRValue"); - } - } - void print(Qualifiers Qs) { - if (!Qs) return printStr("QualNone"); - struct QualName { Qualifiers Q; const char *Name; } Names[] = { - {QualConst, "QualConst"}, - {QualVolatile, "QualVolatile"}, - {QualRestrict, "QualRestrict"}, - }; - for (QualName Name : Names) { - if (Qs & Name.Q) { - printStr(Name.Name); - Qs = Qualifiers(Qs & ~Name.Q); - if (Qs) printStr(" | "); - } - } - } - void print(SpecialSubKind SSK) { - switch (SSK) { - case SpecialSubKind::allocator: - return printStr("SpecialSubKind::allocator"); - case SpecialSubKind::basic_string: - return printStr("SpecialSubKind::basic_string"); - case SpecialSubKind::string: - return printStr("SpecialSubKind::string"); - case SpecialSubKind::istream: - return printStr("SpecialSubKind::istream"); - case SpecialSubKind::ostream: - return printStr("SpecialSubKind::ostream"); - case SpecialSubKind::iostream: - return printStr("SpecialSubKind::iostream"); - } - } - - void newLine() { - printStr("\n"); - for (unsigned I = 0; I != Depth; ++I) - printStr(" "); - PendingNewline = false; - } - - template<typename T> void printWithPendingNewline(T V) { - print(V); - if (wantsNewline(V)) - PendingNewline = true; - } - - template<typename T> void printWithComma(T V) { - if (PendingNewline || wantsNewline(V)) { - printStr(","); - newLine(); - } else { - printStr(", "); - } - - printWithPendingNewline(V); - } - - struct CtorArgPrinter { - DumpVisitor &Visitor; - - template<typename T, typename ...Rest> void operator()(T V, Rest ...Vs) { - if (Visitor.anyWantNewline(V, Vs...)) - Visitor.newLine(); - Visitor.printWithPendingNewline(V); - int PrintInOrder[] = { (Visitor.printWithComma(Vs), 0)..., 0 }; - (void)PrintInOrder; - } - }; - - template<typename NodeT> void operator()(const NodeT *Node) { - Depth += 2; - fprintf(stderr, "%s(", itanium_demangle::NodeKind<NodeT>::name()); - Node->match(CtorArgPrinter{*this}); - fprintf(stderr, ")"); - Depth -= 2; - } - - void operator()(const ForwardTemplateReference *Node) { - Depth += 2; - fprintf(stderr, "ForwardTemplateReference("); - if (Node->Ref && !Node->Printing) { - Node->Printing = true; - CtorArgPrinter{*this}(Node->Ref); - Node->Printing = false; - } else { - CtorArgPrinter{*this}(Node->Index); - } - fprintf(stderr, ")"); - Depth -= 2; - } -}; -} - -void itanium_demangle::Node::dump() const { - DumpVisitor V; - visit(std::ref(V)); - V.newLine(); -} -#endif - -namespace { -class BumpPointerAllocator { - struct BlockMeta { - BlockMeta* Next; - size_t Current; - }; - - static constexpr size_t AllocSize = 4096; - static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); - - alignas(long double) char InitialBuffer[AllocSize]; - BlockMeta* BlockList = nullptr; - - void grow() { - char* NewMeta = static_cast<char *>(std::malloc(AllocSize)); - if (NewMeta == nullptr) - std::terminate(); - BlockList = new (NewMeta) BlockMeta{BlockList, 0}; - } - - void* allocateMassive(size_t NBytes) { - NBytes += sizeof(BlockMeta); - BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes)); - if (NewMeta == nullptr) - std::terminate(); - BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0}; - return static_cast<void*>(NewMeta + 1); - } - -public: - BumpPointerAllocator() - : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {} - - void* allocate(size_t N) { - N = (N + 15u) & ~15u; - if (N + BlockList->Current >= UsableAllocSize) { - if (N > UsableAllocSize) - return allocateMassive(N); - grow(); - } - BlockList->Current += N; - return static_cast<void*>(reinterpret_cast<char*>(BlockList + 1) + - BlockList->Current - N); - } - - void reset() { - while (BlockList) { - BlockMeta* Tmp = BlockList; - BlockList = BlockList->Next; - if (reinterpret_cast<char*>(Tmp) != InitialBuffer) - std::free(Tmp); - } - BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; - } - - ~BumpPointerAllocator() { reset(); } -}; - -class DefaultAllocator { - BumpPointerAllocator Alloc; - -public: - void reset() { Alloc.reset(); } - - template<typename T, typename ...Args> T *makeNode(Args &&...args) { - return new (Alloc.allocate(sizeof(T))) - T(std::forward<Args>(args)...); - } - - void *allocateNodeArray(size_t sz) { - return Alloc.allocate(sizeof(Node *) * sz); - } -}; -} // unnamed namespace - -//===----------------------------------------------------------------------===// -// Code beyond this point should not be synchronized with LLVM. -//===----------------------------------------------------------------------===// - -using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; - -namespace { -enum : int { - demangle_invalid_args = -3, - demangle_invalid_mangled_name = -2, - demangle_memory_alloc_failure = -1, - demangle_success = 0, -}; -} - -namespace __cxxabiv1 { -extern "C" _LIBCXXABI_FUNC_VIS char * -__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { - if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status) - *Status = demangle_invalid_args; - return nullptr; - } - - int InternalStatus = demangle_success; - Demangler Parser(MangledName, MangledName + std::strlen(MangledName)); - OutputStream S; - - Node *AST = Parser.parse(); - - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) - InternalStatus = demangle_memory_alloc_failure; - else { - assert(Parser.ForwardTemplateRefs.empty()); - AST->print(S); - S += '\0'; - if (N != nullptr) - *N = S.getCurrentPosition(); - Buf = S.getBuffer(); - } - - if (Status) - *Status = InternalStatus; - return InternalStatus == demangle_success ? Buf : nullptr; -} -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp deleted file mode 100644 index 8d30e5ce429..00000000000 --- a/lib/libcxxabi/src/cxa_exception.cpp +++ /dev/null @@ -1,757 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" - -#include <exception> // for std::terminate -#include <cstring> // for memset -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" -#include "fallback_malloc.h" -#include "include/atomic_support.h" - -#if __has_feature(address_sanitizer) -extern "C" void __asan_handle_no_return(void); -#endif - -// +---------------------------+-----------------------------+---------------+ -// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | -// +---------------------------+-----------------------------+---------------+ -// ^ -// | -// +-------------------------------------------------------+ -// | -// +---------------------------+-----------------------------+ -// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | -// +---------------------------+-----------------------------+ - -namespace __cxxabiv1 { - -// Utility routines -static -inline -__cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) -{ - return static_cast<__cxa_exception*>(thrown_object) - 1; -} - -// Note: This is never called when exception_header is masquerading as a -// __cxa_dependent_exception. -static -inline -void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) -{ - return static_cast<void*>(exception_header + 1); -} - -// Get the exception object from the unwind pointer. -// Relies on the structure layout, where the unwind pointer is right in -// front of the user's exception object -static -inline -__cxa_exception* -cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) -{ - return cxa_exception_from_thrown_object(unwind_exception + 1 ); -} - -// Round s up to next multiple of a. -static inline -size_t aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); -} - -static inline -size_t cxa_exception_size_from_exception_thrown_size(size_t size) { - return aligned_allocation_size(size + sizeof (__cxa_exception), - alignof(__cxa_exception)); -} - -void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) { - ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); - } - - -static void setOurExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurExceptionClass); -} - -static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { - __setExceptionClass(unwind_exception, kOurDependentExceptionClass); -} - -// Is it one of ours? -uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { -// On x86 and some ARM unwinders, unwind_exception->exception_class is -// a uint64_t. On other ARM unwinders, it is a char[8] -// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf -// So we just copy it into a uint64_t to be sure. - uint64_t exClass; - ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); - return exClass; -} - -bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); -} - -static bool isDependentException(_Unwind_Exception* unwind_exception) { - return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; -} - -// This does not need to be atomic -static inline int incrementHandlerCount(__cxa_exception *exception) { - return ++exception->handlerCount; -} - -// This does not need to be atomic -static inline int decrementHandlerCount(__cxa_exception *exception) { - return --exception->handlerCount; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the exceptionDestructor stored in - exc is called, and then the memory for the exception is deallocated. - - This is never called for a __cxa_dependent_exception. -*/ -static -void -exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(exception_header->terminateHandler); - // Just in case there exists a dependent exception that is pointing to this, - // check the reference count and only destroy this if that count goes to zero. - __cxa_decrement_exception_refcount(unwind_exception + 1); -} - -static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { -// Section 2.5.3 says: -// * For purposes of this ABI, several things are considered exception handlers: -// ** A terminate() call due to a throw. -// and -// * Upon entry, Following initialization of the catch parameter, -// a handler must call: -// * void *__cxa_begin_catch(void *exceptionObject ); - (void) __cxa_begin_catch(&exception_header->unwindHeader); - std::__terminate(exception_header->terminateHandler); -} - -// Return the offset of the __cxa_exception header from the start of the -// allocated buffer. If __cxa_exception's alignment is smaller than the maximum -// useful alignment for the target machine, padding has to be inserted before -// the header to ensure the thrown object that follows the header is -// sufficiently aligned. This happens if _Unwind_exception isn't double-word -// aligned (on Darwin, for example). -static size_t get_cxa_exception_offset() { - struct S { - } __attribute__((aligned)); - - // Compute the maximum alignment for the target machine. - constexpr size_t alignment = std::alignment_of<S>::value; - constexpr size_t excp_size = sizeof(__cxa_exception); - constexpr size_t aligned_size = - (excp_size + alignment - 1) / alignment * alignment; - constexpr size_t offset = aligned_size - excp_size; - static_assert((offset == 0 || - std::alignment_of<_Unwind_Exception>::value < alignment), - "offset is non-zero only if _Unwind_Exception isn't aligned"); - return offset; -} - -extern "C" { - -// Allocate a __cxa_exception object, and zero-fill it. -// Reserve "thrown_size" bytes on the end for the user's exception -// object. Zero-fill the object. If memory can't be allocated, call -// std::terminate. Return a pointer to the memory to be used for the -// user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { - size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); - - // Allocate extra space before the __cxa_exception header to ensure the - // start of the thrown object is sufficiently aligned. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - (char *)__aligned_malloc_with_fallback(header_offset + actual_size); - if (NULL == raw_buffer) - std::terminate(); - __cxa_exception *exception_header = - static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); - std::memset(exception_header, 0, actual_size); - return thrown_object_from_cxa_exception(exception_header); -} - - -// Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { - // Compute the size of the padding before the header. - size_t header_offset = get_cxa_exception_offset(); - char *raw_buffer = - ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; - __aligned_free_with_fallback((void *)raw_buffer); -} - - -// This function shall allocate a __cxa_dependent_exception and -// return a pointer to it. (Really to the object, not past its' end). -// Otherwise, it will work like __cxa_allocate_exception. -void * __cxa_allocate_dependent_exception () { - size_t actual_size = sizeof(__cxa_dependent_exception); - void *ptr = __aligned_malloc_with_fallback(actual_size); - if (NULL == ptr) - std::terminate(); - std::memset(ptr, 0, actual_size); - return ptr; -} - - -// This function shall free a dependent_exception. -// It does not affect the reference count of the primary exception. -void __cxa_free_dependent_exception (void * dependent_exception) { - __aligned_free_with_fallback(dependent_exception); -} - - -// 2.4.3 Throwing the Exception Object -/* -After constructing the exception object with the throw argument value, -the generated code calls the __cxa_throw runtime library routine. This -routine never returns. - -The __cxa_throw routine will do the following: - -* Obtain the __cxa_exception header from the thrown exception object address, -which can be computed as follows: - __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); -* Save the current unexpected_handler and terminate_handler in the __cxa_exception header. -* Save the tinfo and dest arguments in the __cxa_exception header. -* Set the exception_class field in the unwind header. This is a 64-bit value -representing the ASCII string "XXXXC++\0", where "XXXX" is a -vendor-dependent string. That is, for implementations conforming to this -ABI, the low-order 4 bytes of this 64-bit value will be "C++\0". -* Increment the uncaught_exception flag. -* Call _Unwind_RaiseException in the system unwind library, Its argument is the -pointer to the thrown exception, which __cxa_throw itself received as an argument. -__Unwind_RaiseException begins the process of stack unwinding, described -in Section 2.5. In special cases, such as an inability to find a -handler, _Unwind_RaiseException may return. In that case, __cxa_throw -will call terminate, assuming that there was no handler for the -exception. -*/ -void -__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { - __cxa_eh_globals *globals = __cxa_get_globals(); - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - - exception_header->unexpectedHandler = std::get_unexpected(); - exception_header->terminateHandler = std::get_terminate(); - exception_header->exceptionType = tinfo; - exception_header->exceptionDestructor = dest; - setOurExceptionClass(&exception_header->unwindHeader); - exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. - globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local - - exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; - -#if __has_feature(address_sanitizer) - // Inform the ASan runtime that now might be a good time to clean stuff up. - __asan_handle_no_return(); -#endif - -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - // This only happens when there is no handler, or some unexpected unwinding - // error happens. - failed_throw(exception_header); -} - - -// 2.5.3 Exception Handlers -/* -The adjusted pointer is computed by the personality routine during phase 1 - and saved in the exception header (either __cxa_exception or - __cxa_dependent_exception). - - Requires: exception is native -*/ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast<void*>( - static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); -#else - return cxa_exception_from_exception_unwind_exception( - static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; -#endif -} - -#if defined(_LIBCXXABI_ARM_EHABI) -/* -The routine to be called before the cleanup. This will save __cxa_exception in -__cxa_eh_globals, so that __cxa_end_cleanup() can recover later. -*/ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception(unwind_exception); - - if (__isOurExceptionClass(unwind_exception)) - { - if (0 == exception_header->propagationCount) - { - exception_header->nextPropagatingException = globals->propagatingExceptions; - globals->propagatingExceptions = exception_header; - } - ++exception_header->propagationCount; - } - else - { - // If the propagatingExceptions stack is not empty, since we can't - // chain the foreign exception, terminate it. - if (NULL != globals->propagatingExceptions) - std::terminate(); - globals->propagatingExceptions = exception_header; - } - return true; -} - -/* -The routine to be called after the cleanup has been performed. It will get the -propagating __cxa_exception from __cxa_eh_globals, and continue the stack -unwinding with _Unwind_Resume. - -According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any -register, thus we have to write this function in assembly so that we can save -{r1, r2, r3}. We don't have to save r0 because it is the return value and the -first argument to _Unwind_Resume(). In addition, we are saving r4 in order to -align the stack to 16 bytes, even though it is a callee-save register. -*/ -__attribute__((used)) static _Unwind_Exception * -__cxa_end_cleanup_impl() -{ - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->propagatingExceptions; - if (NULL == exception_header) - { - // It seems that __cxa_begin_cleanup() is not called properly. - // We have no choice but terminate the program now. - std::terminate(); - } - - if (__isOurExceptionClass(&exception_header->unwindHeader)) - { - --exception_header->propagationCount; - if (0 == exception_header->propagationCount) - { - globals->propagatingExceptions = exception_header->nextPropagatingException; - exception_header->nextPropagatingException = NULL; - } - } - else - { - globals->propagatingExceptions = NULL; - } - return &exception_header->unwindHeader; -} - -asm ( - " .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" - " .globl __cxa_end_cleanup\n" - " .type __cxa_end_cleanup,%function\n" - "__cxa_end_cleanup:\n" - " push {r1, r2, r3, r4}\n" - " bl __cxa_end_cleanup_impl\n" - " pop {r1, r2, r3, r4}\n" - " bl _Unwind_Resume\n" - " bl abort\n" - " .popsection" -); -#endif // defined(_LIBCXXABI_ARM_EHABI) - -/* -This routine can catch foreign or native exceptions. If native, the exception -can be a primary or dependent variety. This routine may remain blissfully -ignorant of whether the native exception is primary or dependent. - -If the exception is native: -* Increment's the exception's handler count. -* Push the exception on the stack of currently-caught exceptions if it is not - already there (from a rethrow). -* Decrements the uncaught_exception count. -* Returns the adjusted pointer to the exception object, which is stored in - the __cxa_exception by the personality routine. - -If the exception is foreign, this means it did not originate from one of throw -routines. The foreign exception does not necessarily have a __cxa_exception -header. However we can catch it here with a catch (...), or with a call -to terminate or unexpected during unwinding. -* Do not try to increment the exception's handler count, we don't know where - it is. -* Push the exception on the stack of currently-caught exceptions only if the - stack is empty. The foreign exception has no way to link to the current - top of stack. If the stack is not empty, call terminate. Even with an - empty stack, this is hacked in by pushing a pointer to an imaginary - __cxa_exception block in front of the foreign exception. It would be better - if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it - doesn't. It has a stack of __cxa_exception (which has a next* in it). -* Do not decrement the uncaught_exception count because we didn't increment it - in __cxa_throw (or one of our rethrow functions). -* If we haven't terminated, assume the exception object is just past the - _Unwind_Exception and return a pointer to that. -*/ -void* -__cxa_begin_catch(void* unwind_arg) throw() -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); - bool native_exception = __isOurExceptionClass(unwind_exception); - __cxa_eh_globals* globals = __cxa_get_globals(); - // exception_header is a hackish offset from a foreign exception, but it - // works as long as we're careful not to try to access any __cxa_exception - // parts. - __cxa_exception* exception_header = - cxa_exception_from_exception_unwind_exception - ( - static_cast<_Unwind_Exception*>(unwind_exception) - ); - if (native_exception) - { - // Increment the handler count, removing the flag about being rethrown - exception_header->handlerCount = exception_header->handlerCount < 0 ? - -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; - // place the exception on the top of the stack if it's not already - // there by a previous rethrow - if (exception_header != globals->caughtExceptions) - { - exception_header->nextException = globals->caughtExceptions; - globals->caughtExceptions = exception_header; - } - globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local -#if defined(_LIBCXXABI_ARM_EHABI) - return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]); -#else - return exception_header->adjustedPtr; -#endif - } - // Else this is a foreign exception - // If the caughtExceptions stack is not empty, terminate - if (globals->caughtExceptions != 0) - std::terminate(); - // Push the foreign exception on to the stack - globals->caughtExceptions = exception_header; - return unwind_exception + 1; -} - - -/* -Upon exit for any reason, a handler must call: - void __cxa_end_catch (); - -This routine can be called for either a native or foreign exception. -For a native exception: -* Locates the most recently caught exception and decrements its handler count. -* Removes the exception from the caught exception stack, if the handler count goes to zero. -* If the handler count goes down to zero, and the exception was not re-thrown - by throw, it locates the primary exception (which may be the same as the one - it's handling) and decrements its reference count. If that reference count - goes to zero, the function destroys the exception. In any case, if the current - exception is a dependent exception, it destroys that. - -For a foreign exception: -* If it has been rethrown, there is nothing to do. -* Otherwise delete the exception and pop the catch stack to empty. -*/ -void __cxa_end_catch() { - static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), - "sizeof(__cxa_exception) must be equal to " - "sizeof(__cxa_dependent_exception)"); - static_assert(__builtin_offsetof(__cxa_exception, referenceCount) == - __builtin_offsetof(__cxa_dependent_exception, - primaryException), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - static_assert(__builtin_offsetof(__cxa_exception, handlerCount) == - __builtin_offsetof(__cxa_dependent_exception, handlerCount), - "the layout of __cxa_exception must match the layout of " - "__cxa_dependent_exception"); - __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch - __cxa_exception* exception_header = globals->caughtExceptions; - // If we've rethrown a foreign exception, then globals->caughtExceptions - // will have been made an empty stack by __cxa_rethrow() and there is - // nothing more to be done. Do nothing! - if (NULL != exception_header) - { - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // This is a native exception - if (exception_header->handlerCount < 0) - { - // The exception has been rethrown by __cxa_rethrow, so don't delete it - if (0 == incrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // but don't destroy - } - // Keep handlerCount negative in case there are nested catch's - // that need to be told that this exception is rethrown. Don't - // erase this rethrow flag until the exception is recaught. - } - else - { - // The native exception has not been rethrown - if (0 == decrementHandlerCount(exception_header)) - { - // Remove from the chain of uncaught exceptions - globals->caughtExceptions = exception_header->nextException; - // Destroy this exception, being careful to distinguish - // between dependent and primary exceptions - if (isDependentException(&exception_header->unwindHeader)) - { - // Reset exception_header to primaryException and deallocate the dependent exception - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = - cxa_exception_from_thrown_object(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); - } - // Destroy the primary exception only if its referenceCount goes to 0 - // (this decrement must be atomic) - __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); - } - } - } - else - { - // The foreign exception has not been rethrown. Pop the stack - // and delete it. If there are nested catch's and they try - // to touch a foreign exception in any way, that is undefined - // behavior. They likely can't since the only way to catch - // a foreign exception is with catch (...)! - _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); - globals->caughtExceptions = 0; - } - } -} - -// Note: exception_header may be masquerading as a __cxa_dependent_exception -// and that's ok. exceptionType is there too. -// However watch out for foreign exceptions. Return null for them. -std::type_info *__cxa_current_exception_type() { -// get the current exception - __cxa_eh_globals *globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there have never been any exceptions, there are none now. - __cxa_exception *exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; - return exception_header->exceptionType; -} - -// 2.5.4 Rethrowing Exceptions -/* This routine can rethrow native or foreign exceptions. -If the exception is native: -* marks the exception object on top of the caughtExceptions stack - (in an implementation-defined way) as being rethrown. -* If the caughtExceptions stack is empty, it calls terminate() - (see [C++FDIS] [except.throw], 15.1.8). -* It then calls _Unwind_RaiseException which should not return - (terminate if it does). - Note: exception_header may be masquerading as a __cxa_dependent_exception - and that's ok. -*/ -void __cxa_rethrow() { - __cxa_eh_globals* globals = __cxa_get_globals(); - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - std::terminate(); // throw; called outside of a exception handler - bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); - if (native_exception) - { - // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) - exception_header->handlerCount = -exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary - } - else // this is a foreign exception - { - // The only way to communicate to __cxa_end_catch that we've rethrown - // a foreign exception, so don't delete us, is to pop the stack here - // which must be empty afterwards. Then __cxa_end_catch will do - // nothing - globals->caughtExceptions = 0; - } -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); -#else - _Unwind_RaiseException(&exception_header->unwindHeader); -#endif - - // If we get here, some kind of unwinding error has occurred. - // There is some weird code generation bug happening with - // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) - // If we call failed_throw here. Turns up with -O2 or higher, and -Os. - __cxa_begin_catch(&exception_header->unwindHeader); - if (native_exception) - std::__terminate(exception_header->terminateHandler); - // Foreign exception: can't get exception_header->terminateHandler - std::terminate(); -} - -/* - If thrown_object is not null, atomically increment the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); - } -} - -/* - If thrown_object is not null, atomically decrement the referenceCount field - of the __cxa_exception header associated with the thrown object referred to - by thrown_object. If the referenceCount drops to zero, destroy and - deallocate the exception. - - Requires: If thrown_object is not NULL, it is a native exception. -*/ -_LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != NULL ) - { - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) - { - if (NULL != exception_header->exceptionDestructor) - exception_header->exceptionDestructor(thrown_object); - __cxa_free_exception(thrown_object); - } - } -} - -/* - Returns a pointer to the thrown object (if any) at the top of the - caughtExceptions stack. Atomically increment the exception's referenceCount. - If there is no such thrown object or if the thrown object is foreign, - returns null. - - We can use __cxa_get_globals_fast here to get the globals because if there have - been no exceptions thrown, ever, on this thread, we can return NULL without - the need to allocate the exception-handling globals. -*/ -void *__cxa_current_primary_exception() throw() { -// get the current exception - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (NULL == globals) - return NULL; // If there are no globals, there is no exception - __cxa_exception* exception_header = globals->caughtExceptions; - if (NULL == exception_header) - return NULL; // No current exception - if (!__isOurExceptionClass(&exception_header->unwindHeader)) - return NULL; // Can't capture a foreign exception (no way to refcount it) - if (isDependentException(&exception_header->unwindHeader)) { - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(exception_header); - exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); - } - void* thrown_object = thrown_object_from_cxa_exception(exception_header); - __cxa_increment_exception_refcount(thrown_object); - return thrown_object; -} - -/* - If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler - stored in exc is called. Otherwise the referenceCount stored in the - primary exception is decremented, destroying the primary if necessary. - Finally the dependent exception is destroyed. -*/ -static -void -dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) -{ - __cxa_dependent_exception* dep_exception_header = - reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; - if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) - std::__terminate(dep_exception_header->terminateHandler); - __cxa_decrement_exception_refcount(dep_exception_header->primaryException); - __cxa_free_dependent_exception(dep_exception_header); -} - -/* - If thrown_object is not null, allocate, initialize and throw a dependent - exception. -*/ -void -__cxa_rethrow_primary_exception(void* thrown_object) -{ - if ( thrown_object != NULL ) - { - // thrown_object guaranteed to be native because - // __cxa_current_primary_exception returns NULL for foreign exceptions - __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - __cxa_dependent_exception* dep_exception_header = - static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); - dep_exception_header->primaryException = thrown_object; - __cxa_increment_exception_refcount(thrown_object); - dep_exception_header->exceptionType = exception_header->exceptionType; - dep_exception_header->unexpectedHandler = std::get_unexpected(); - dep_exception_header->terminateHandler = std::get_terminate(); - setDependentExceptionClass(&dep_exception_header->unwindHeader); - __cxa_get_globals()->uncaughtExceptions += 1; - dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; -#ifdef __USING_SJLJ_EXCEPTIONS__ - _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); -#else - _Unwind_RaiseException(&dep_exception_header->unwindHeader); -#endif - // Some sort of unwinding error. Note that terminate is a handler. - __cxa_begin_catch(&dep_exception_header->unwindHeader); - } - // If we return client will call terminate() -} - -bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } - -unsigned int -__cxa_uncaught_exceptions() throw() -{ - // This does not report foreign exceptions in flight - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - if (globals == 0) - return 0; - return globals->uncaughtExceptions; -} - -} // extern "C" - -} // abi diff --git a/lib/libcxxabi/src/cxa_exception.hpp b/lib/libcxxabi/src/cxa_exception.hpp deleted file mode 100644 index 6d98e11a623..00000000000 --- a/lib/libcxxabi/src/cxa_exception.hpp +++ /dev/null @@ -1,120 +0,0 @@ -//===------------------------- cxa_exception.hpp --------------------------===// -// -// 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 "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -#ifndef _CXA_EXCEPTION_H -#define _CXA_EXCEPTION_H - -#include <exception> // for std::unexpected_handler and std::terminate_handler -#include "cxxabi.h" -#include "unwind.h" - -namespace __cxxabiv1 { - -static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 -static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 -static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ - -uint64_t __getExceptionClass (const _Unwind_Exception*); -void __setExceptionClass ( _Unwind_Exception*, uint64_t); -bool __isOurExceptionClass(const _Unwind_Exception*); - -struct _LIBCXXABI_HIDDEN __cxa_exception { -#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) - // This is a new field to support C++ 0x exception_ptr. - // For binary compatibility it is at the start of this - // struct which is prepended to the object thrown in - // __cxa_allocate_exception. - size_t referenceCount; -#endif - - // Manage the exception object itself. - std::type_info *exceptionType; - void (*exceptionDestructor)(void *); - std::unexpected_handler unexpectedHandler; - std::terminate_handler terminateHandler; - - __cxa_exception *nextException; - - int handlerCount; - -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* nextPropagatingException; - int propagationCount; -#else - int handlerSwitchValue; - const unsigned char *actionRecord; - const unsigned char *languageSpecificData; - void *catchTemp; - void *adjustedPtr; -#endif - -#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) - // This is a new field to support C++ 0x exception_ptr. - // For binary compatibility it is placed where the compiler - // previously adding padded to 64-bit align unwindHeader. - size_t referenceCount; -#endif - _Unwind_Exception unwindHeader; -}; - -// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html -// The layout of this structure MUST match the layout of __cxa_exception, with -// primaryException instead of referenceCount. -struct _LIBCXXABI_HIDDEN __cxa_dependent_exception { -#if defined(__LP64__) || defined(_LIBCXXABI_ARM_EHABI) - void* primaryException; -#endif - - std::type_info *exceptionType; - void (*exceptionDestructor)(void *); - std::unexpected_handler unexpectedHandler; - std::terminate_handler terminateHandler; - - __cxa_exception *nextException; - - int handlerCount; - -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* nextPropagatingException; - int propagationCount; -#else - int handlerSwitchValue; - const unsigned char *actionRecord; - const unsigned char *languageSpecificData; - void * catchTemp; - void *adjustedPtr; -#endif - -#if !defined(__LP64__) && !defined(_LIBCXXABI_ARM_EHABI) - void* primaryException; -#endif - _Unwind_Exception unwindHeader; -}; - -struct _LIBCXXABI_HIDDEN __cxa_eh_globals { - __cxa_exception * caughtExceptions; - unsigned int uncaughtExceptions; -#if defined(_LIBCXXABI_ARM_EHABI) - __cxa_exception* propagatingExceptions; -#endif -}; - -extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals (); -extern "C" _LIBCXXABI_FUNC_VIS __cxa_eh_globals * __cxa_get_globals_fast (); - -extern "C" _LIBCXXABI_FUNC_VIS void * __cxa_allocate_dependent_exception (); -extern "C" _LIBCXXABI_FUNC_VIS void __cxa_free_dependent_exception (void * dependent_exception); - -} // namespace __cxxabiv1 - -#endif // _CXA_EXCEPTION_H diff --git a/lib/libcxxabi/src/cxa_exception_storage.cpp b/lib/libcxxabi/src/cxa_exception_storage.cpp deleted file mode 100644 index c641e0225f8..00000000000 --- a/lib/libcxxabi/src/cxa_exception_storage.cpp +++ /dev/null @@ -1,102 +0,0 @@ -//===--------------------- cxa_exception_storage.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 storage for the "Caught Exception Stack" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html (section 2.2.2) -// -//===----------------------------------------------------------------------===// - -#include "cxa_exception.hpp" - -#include <__threading_support> - -#if defined(_LIBCXXABI_HAS_NO_THREADS) - -namespace __cxxabiv1 { -extern "C" { - static __cxa_eh_globals eh_globals; - __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } - __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } - } -} - -#elif defined(HAS_THREAD_LOCAL) - -namespace __cxxabiv1 { - -namespace { - __cxa_eh_globals * __globals () { - static thread_local __cxa_eh_globals eh_globals; - return &eh_globals; - } - } - -extern "C" { - __cxa_eh_globals * __cxa_get_globals () { return __globals (); } - __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } - } -} - -#else - -#include "abort_message.h" -#include "fallback_malloc.h" - -// In general, we treat all threading errors as fatal. -// We cannot call std::terminate() because that will in turn -// call __cxa_get_globals() and cause infinite recursion. - -namespace __cxxabiv1 { -namespace { - std::__libcpp_tls_key key_; - std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; - - void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) { - __free_with_fallback ( p ); - if ( 0 != std::__libcpp_tls_set ( key_, NULL ) ) - abort_message("cannot zero out thread value for __cxa_get_globals()"); - } - - void construct_ () { - if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) ) - abort_message("cannot create thread specific key for __cxa_get_globals()"); - } -} - -extern "C" { - __cxa_eh_globals * __cxa_get_globals () { - // Try to get the globals for this thread - __cxa_eh_globals* retVal = __cxa_get_globals_fast (); - - // If this is the first time we've been asked for these globals, create them - if ( NULL == retVal ) { - retVal = static_cast<__cxa_eh_globals*> - (__calloc_with_fallback (1, sizeof (__cxa_eh_globals))); - if ( NULL == retVal ) - abort_message("cannot allocate __cxa_eh_globals"); - if ( 0 != std::__libcpp_tls_set ( key_, retVal ) ) - abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); - } - return retVal; - } - - // Note that this implementation will reliably return NULL if not - // preceded by a call to __cxa_get_globals(). This is an extension - // to the Itanium ABI and is taken advantage of in several places in - // libc++abi. - __cxa_eh_globals * __cxa_get_globals_fast () { - // First time through, create the key. - if (0 != std::__libcpp_execute_once(&flag_, construct_)) - abort_message("execute once failure in __cxa_get_globals_fast()"); -// static int init = construct_(); - return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); - } - -} -} -#endif diff --git a/lib/libcxxabi/src/cxa_guard.cpp b/lib/libcxxabi/src/cxa_guard.cpp deleted file mode 100644 index f4c2a184dc5..00000000000 --- a/lib/libcxxabi/src/cxa_guard.cpp +++ /dev/null @@ -1,265 +0,0 @@ -//===---------------------------- cxa_guard.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 "__cxxabi_config.h" - -#include "abort_message.h" -#include <__threading_support> - -#include <stdint.h> - -/* - This implementation must be careful to not call code external to this file - which will turn around and try to call __cxa_guard_acquire reentrantly. - For this reason, the headers of this file are as restricted as possible. - Previous implementations of this code for __APPLE__ have used - std::__libcpp_mutex_lock and the abort_message utility without problem. This - implementation also uses std::__libcpp_condvar_wait which has tested - to not be a problem. -*/ - -namespace __cxxabiv1 -{ - -namespace -{ - -#ifdef __arm__ -// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must -// be statically initialized to 0. -typedef uint32_t guard_type; - -inline void set_initialized(guard_type* guard_object) { - *guard_object |= 1; -} -#else -typedef uint64_t guard_type; - -void set_initialized(guard_type* guard_object) { - char* initialized = (char*)guard_object; - *initialized = 1; -} -#endif - -#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__)) -#ifdef __arm__ - -// Test the lowest bit. -inline bool is_initialized(guard_type* guard_object) { - return (*guard_object) & 1; -} - -#else - -bool is_initialized(guard_type* guard_object) { - char* initialized = (char*)guard_object; - return *initialized; -} - -#endif -#endif - -#ifndef _LIBCXXABI_HAS_NO_THREADS -std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER; -std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER; -#endif - -#if defined(__APPLE__) && !defined(__arm__) - -typedef uint32_t lock_type; - -#if __LITTLE_ENDIAN__ - -inline -lock_type -get_lock(uint64_t x) -{ - return static_cast<lock_type>(x >> 32); -} - -inline -void -set_lock(uint64_t& x, lock_type y) -{ - x = static_cast<uint64_t>(y) << 32; -} - -#else // __LITTLE_ENDIAN__ - -inline -lock_type -get_lock(uint64_t x) -{ - return static_cast<lock_type>(x); -} - -inline -void -set_lock(uint64_t& x, lock_type y) -{ - x = y; -} - -#endif // __LITTLE_ENDIAN__ - -#else // !__APPLE__ || __arm__ - -typedef bool lock_type; - -#if !defined(__arm__) -static_assert(std::is_same<guard_type, uint64_t>::value, ""); - -inline lock_type get_lock(uint64_t x) -{ - union - { - uint64_t guard; - uint8_t lock[2]; - } f = {x}; - return f.lock[1] != 0; -} - -inline void set_lock(uint64_t& x, lock_type y) -{ - union - { - uint64_t guard; - uint8_t lock[2]; - } f = {0}; - f.lock[1] = y; - x = f.guard; -} -#else // defined(__arm__) -static_assert(std::is_same<guard_type, uint32_t>::value, ""); - -inline lock_type get_lock(uint32_t x) -{ - union - { - uint32_t guard; - uint8_t lock[2]; - } f = {x}; - return f.lock[1] != 0; -} - -inline void set_lock(uint32_t& x, lock_type y) -{ - union - { - uint32_t guard; - uint8_t lock[2]; - } f = {0}; - f.lock[1] = y; - x = f.guard; -} - -#endif // !defined(__arm__) - -#endif // __APPLE__ && !__arm__ - -} // unnamed namespace - -extern "C" -{ - -#ifndef _LIBCXXABI_HAS_NO_THREADS -_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { - char* initialized = (char*)guard_object; - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_acquire failed to acquire mutex"); - int result = *initialized == 0; - if (result) - { -#if defined(__APPLE__) && !defined(__arm__) - // This is a special-case pthread dependency for Mac. We can't pull this - // out into libcxx's threading API (__threading_support) because not all - // supported Mac environments provide this function (in pthread.h). To - // make it possible to build/use libcxx in those environments, we have to - // keep this pthread dependency local to libcxxabi. If there is some - // convenient way to detect precisely when pthread_mach_thread_np is - // available in a given Mac environment, it might still be possible to - // bury this dependency in __threading_support. - #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD - const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id()); - #else - #error "How do I pthread_mach_thread_np()?" - #endif - lock_type lock = get_lock(*guard_object); - if (lock) - { - // if this thread set lock for this same guard_object, abort - if (lock == id) - abort_message("__cxa_guard_acquire detected deadlock"); - do - { - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) - abort_message("__cxa_guard_acquire condition variable wait failed"); - lock = get_lock(*guard_object); - } while (lock); - result = !is_initialized(guard_object); - if (result) - set_lock(*guard_object, id); - } - else - set_lock(*guard_object, id); -#else // !__APPLE__ || __arm__ - while (get_lock(*guard_object)) - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) - abort_message("__cxa_guard_acquire condition variable wait failed"); - result = *initialized == 0; - if (result) - set_lock(*guard_object, true); -#endif // !__APPLE__ || __arm__ - } - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_acquire failed to release mutex"); - return result; -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_release failed to acquire mutex"); - *guard_object = 0; - set_initialized(guard_object); - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_release failed to release mutex"); - if (std::__libcpp_condvar_broadcast(&guard_cv)) - abort_message("__cxa_guard_release failed to broadcast condition variable"); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("__cxa_guard_abort failed to acquire mutex"); - *guard_object = 0; - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("__cxa_guard_abort failed to release mutex"); - if (std::__libcpp_condvar_broadcast(&guard_cv)) - abort_message("__cxa_guard_abort failed to broadcast condition variable"); -} - -#else // _LIBCXXABI_HAS_NO_THREADS - -_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { - return !is_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { - *guard_object = 0; - set_initialized(guard_object); -} - -_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { - *guard_object = 0; -} - -#endif // !_LIBCXXABI_HAS_NO_THREADS - -} // extern "C" - -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp deleted file mode 100644 index 8c26bd0b1a6..00000000000 --- a/lib/libcxxabi/src/cxa_handlers.cpp +++ /dev/null @@ -1,110 +0,0 @@ -//===------------------------- cxa_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 functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. -//===----------------------------------------------------------------------===// - -#include <stdexcept> -#include <new> -#include <exception> -#include "abort_message.h" -#include "cxxabi.h" -#include "cxa_handlers.hpp" -#include "cxa_exception.hpp" -#include "private_typeinfo.h" -#include "include/atomic_support.h" - -namespace std -{ - -unexpected_handler -get_unexpected() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire); -} - -void -__unexpected(unexpected_handler func) -{ - func(); - // unexpected handler should not return - abort_message("unexpected_handler unexpectedly returned"); -} - -__attribute__((noreturn)) -void -unexpected() -{ - __unexpected(get_unexpected()); -} - -terminate_handler -get_terminate() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire); -} - -void -__terminate(terminate_handler func) _NOEXCEPT -{ -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - func(); - // handler should not return - abort_message("terminate_handler unexpectedly returned"); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - // handler should not throw exception - abort_message("terminate_handler unexpectedly threw an exception"); - } -#endif // _LIBCXXABI_NO_EXCEPTIONS -} - -__attribute__((noreturn)) -void -terminate() _NOEXCEPT -{ - // 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 (exception_header) - { - _Unwind_Exception* unwind_exception = - reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; - if (__isOurExceptionClass(unwind_exception)) - __terminate(exception_header->terminateHandler); - } - } - __terminate(get_terminate()); -} - -extern "C" { -new_handler __cxa_new_handler = 0; -} - -new_handler -set_new_handler(new_handler handler) _NOEXCEPT -{ - return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); -} - -new_handler -get_new_handler() _NOEXCEPT -{ - return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire); -} - -} // std diff --git a/lib/libcxxabi/src/cxa_handlers.hpp b/lib/libcxxabi/src/cxa_handlers.hpp deleted file mode 100644 index 14c0e10119d..00000000000 --- a/lib/libcxxabi/src/cxa_handlers.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//===------------------------- cxa_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 functionality associated with the terminate_handler, -// unexpected_handler, and new_handler. -//===----------------------------------------------------------------------===// - -#ifndef _CXA_HANDLERS_H -#define _CXA_HANDLERS_H - -#include <__cxxabi_config.h> - -#include <exception> - -namespace std -{ - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN -void -__unexpected(unexpected_handler func); - -_LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN -void -__terminate(terminate_handler func) _NOEXCEPT; - -} // std - -extern "C" -{ - -_LIBCXXABI_DATA_VIS extern void (*__cxa_terminate_handler)(); -_LIBCXXABI_DATA_VIS extern void (*__cxa_unexpected_handler)(); -_LIBCXXABI_DATA_VIS extern void (*__cxa_new_handler)(); - -/* - - At some point in the future these three symbols will become - C++11 atomic variables: - - extern std::atomic<std::terminate_handler> __cxa_terminate_handler; - extern std::atomic<std::unexpected_handler> __cxa_unexpected_handler; - extern std::atomic<std::new_handler> __cxa_new_handler; - - This change will not impact their ABI. But it will allow for a - portable performance optimization. - -*/ - -} // extern "C" - -#endif // _CXA_HANDLERS_H diff --git a/lib/libcxxabi/src/cxa_noexception.cpp b/lib/libcxxabi/src/cxa_noexception.cpp deleted file mode 100644 index 8d5b5f2d00b..00000000000 --- a/lib/libcxxabi/src/cxa_noexception.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// -//===----------------------------------------------------------------------===// - -// Support functions for the no-exceptions libc++ library - -#include "cxxabi.h" - -#include <exception> // for std::terminate -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" - -namespace __cxxabiv1 { - -extern "C" { - -void -__cxa_increment_exception_refcount(void *thrown_object) throw() { - if (thrown_object != nullptr) - std::terminate(); -} - -void -__cxa_decrement_exception_refcount(void *thrown_object) throw() { - if (thrown_object != nullptr) - std::terminate(); -} - - -void *__cxa_current_primary_exception() throw() { return nullptr; } - -void -__cxa_rethrow_primary_exception(void* thrown_object) { - if (thrown_object != nullptr) - std::terminate(); -} - -bool -__cxa_uncaught_exception() throw() { return false; } - -unsigned int -__cxa_uncaught_exceptions() throw() { return 0; } - -} // extern "C" - -// provide dummy implementations for the 'no exceptions' case. -uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; } -void __setExceptionClass ( _Unwind_Exception*, uint64_t) {} -bool __isOurExceptionClass(const _Unwind_Exception*) { return false; } - -} // abi diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp deleted file mode 100644 index 468461df54a..00000000000 --- a/lib/libcxxabi/src/cxa_personality.cpp +++ /dev/null @@ -1,1325 +0,0 @@ -//===------------------------- cxa_exception.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the "Exception Handling APIs" -// http://mentorembedded.github.io/cxx-abi/abi-eh.html -// http://www.intel.com/design/itanium/downloads/245358.htm -// -//===----------------------------------------------------------------------===// - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <typeinfo> - -#include "__cxxabi_config.h" -#include "cxa_exception.hpp" -#include "cxa_handlers.hpp" -#include "private_typeinfo.h" -#include "unwind.h" - -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -#include <windows.h> -#include <winnt.h> - -extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, - void *, PCONTEXT, - PDISPATCHER_CONTEXT, - _Unwind_Personality_Fn); -#endif - -/* - Exception Header Layout: - -+---------------------------+-----------------------------+---------------+ -| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | -+---------------------------+-----------------------------+---------------+ - ^ - | - +-------------------------------------------------------+ - | -+---------------------------+-----------------------------+ -| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | -+---------------------------+-----------------------------+ - - Exception Handling Table Layout: - -+-----------------+--------+ -| lpStartEncoding | (char) | -+---------+-------+--------+---------------+-----------------------+ -| lpStart | (encoded with lpStartEncoding) | defaults to funcStart | -+---------+-----+--------+-----------------+---------------+-------+ -| ttypeEncoding | (char) | Encoding of the type_info table | -+---------------+-+------+----+----------------------------+----------------+ -| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null | -+-----------------++--------+-+----------------------------+----------------+ -| callSiteEncoding | (char) | Encoding for Call Site Table | -+------------------+--+-----+-----+------------------------+--------------------------+ -| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | -+---------------------+-----------+---------------------------------------------------+ -#ifndef __USING_SJLJ_EXCEPTIONS__ -+---------------------+-----------+------------------------------------------------+ -| Beginning of Call Site Table The current ip lies within the | -| ... (start, length) range of one of these | -| call sites. There may be action needed. | -| +-------------+---------------------------------+------------------------------+ | -| | start | (encoded with callSiteEncoding) | offset relative to funcStart | | -| | length | (encoded with callSiteEncoding) | length of code fragment | | -| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | | -| | actionEntry | (ULEB128) | Action Table Index 1-based | | -| | | | actionEntry == 0 -> cleanup | | -| +-------------+---------------------------------+------------------------------+ | -| ... | -+----------------------------------------------------------------------------------+ -#else // __USING_SJLJ_EXCEPTIONS__ -+---------------------+-----------+------------------------------------------------+ -| Beginning of Call Site Table The current ip is a 1-based index into | -| ... this table. Or it is -1 meaning no | -| action is needed. Or it is 0 meaning | -| terminate. | -| +-------------+---------------------------------+------------------------------+ | -| | landingPad | (ULEB128) | offset relative to lpStart | | -| | actionEntry | (ULEB128) | Action Table Index 1-based | | -| | | | actionEntry == 0 -> cleanup | | -| +-------------+---------------------------------+------------------------------+ | -| ... | -+----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ -+---------------------------------------------------------------------+ -| Beginning of Action Table ttypeIndex == 0 : cleanup | -| ... ttypeIndex > 0 : catch | -| ttypeIndex < 0 : exception spec | -| +--------------+-----------+--------------------------------------+ | -| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | | -| | actionOffset | (SLEB128) | Offset into next Action Table entry | | -| +--------------+-----------+--------------------------------------+ | -| ... | -+---------------------------------------------------------------------+-----------------+ -| type_info Table, but classInfoOffset does *not* point here! | -| +----------------+------------------------------------------------+-----------------+ | -| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | | -| +----------------+------------------------------------------------+-----------------+ | -| ... | -| +----------------+------------------------------------------------+-----------------+ | -| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | | -| +----------------+------------------------------------------------+-----------------+ | -| +---------------------------------------+-----------+------------------------------+ | -| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | | -| | ... | (ULEB128) | | | -| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | | -| | 0 | (ULEB128) | | | -| +---------------------------------------+------------------------------------------+ | -| ... | -| +---------------------------------------+------------------------------------------+ | -| | 0 | (ULEB128) | throw() | | -| +---------------------------------------+------------------------------------------+ | -| ... | -| +---------------------------------------+------------------------------------------+ | -| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | | -| | ... | (ULEB128) | | | -| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | | -| | 0 | (ULEB128) | | | -| +---------------------------------------+------------------------------------------+ | -+---------------------------------------------------------------------------------------+ - -Notes: - -* ttypeIndex in the Action Table, and in the exception spec table, is an index, - not a byte count, if positive. It is a negative index offset of - classInfoOffset and the sizeof entry depends on ttypeEncoding. - But if ttypeIndex is negative, it is a positive 1-based byte offset into the - type_info Table. - And if ttypeIndex is zero, it refers to a catch (...). - -* landingPad can be 0, this implies there is nothing to be done. - -* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done - @landingPad. - -* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in - the Action Table with ttypeIndex == 0. -*/ - -namespace __cxxabiv1 -{ - -namespace -{ - -template <class AsType> -uintptr_t readPointerHelper(const uint8_t*& p) { - AsType value; - memcpy(&value, p, sizeof(AsType)); - p += sizeof(AsType); - return static_cast<uintptr_t>(value); -} - -} // end namespace - -extern "C" -{ - -// private API - -// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp - -// DWARF Constants -enum -{ - DW_EH_PE_absptr = 0x00, - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - DW_EH_PE_indirect = 0x80, - DW_EH_PE_omit = 0xFF -}; - -/// Read a uleb128 encoded value and advance pointer -/// See Variable Length Data Appendix C in: -/// @link http://dwarfstd.org/Dwarf4.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @returns decoded value -static -uintptr_t -readULEB128(const uint8_t** data) -{ - uintptr_t result = 0; - uintptr_t shift = 0; - unsigned char byte; - const uint8_t *p = *data; - do - { - byte = *p++; - result |= static_cast<uintptr_t>(byte & 0x7F) << shift; - shift += 7; - } while (byte & 0x80); - *data = p; - return result; -} - -/// Read a sleb128 encoded value and advance pointer -/// See Variable Length Data Appendix C in: -/// @link http://dwarfstd.org/Dwarf4.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @returns decoded value -static -intptr_t -readSLEB128(const uint8_t** data) -{ - uintptr_t result = 0; - uintptr_t shift = 0; - unsigned char byte; - const uint8_t *p = *data; - do - { - byte = *p++; - result |= static_cast<uintptr_t>(byte & 0x7F) << shift; - shift += 7; - } while (byte & 0x80); - *data = p; - if ((byte & 0x40) && (shift < (sizeof(result) << 3))) - result |= static_cast<uintptr_t>(~0) << shift; - return static_cast<intptr_t>(result); -} - -/// Read a pointer encoded value and advance pointer -/// See Variable Length Data in: -/// @link http://dwarfstd.org/Dwarf3.pdf @unlink -/// @param data reference variable holding memory pointer to decode from -/// @param encoding dwarf encoding type -/// @returns decoded value -static -uintptr_t -readEncodedPointer(const uint8_t** data, uint8_t encoding) -{ - uintptr_t result = 0; - if (encoding == DW_EH_PE_omit) - return result; - const uint8_t* p = *data; - // first get value - switch (encoding & 0x0F) - { - case DW_EH_PE_absptr: - result = readPointerHelper<uintptr_t>(p); - break; - case DW_EH_PE_uleb128: - result = readULEB128(&p); - break; - case DW_EH_PE_sleb128: - result = static_cast<uintptr_t>(readSLEB128(&p)); - break; - case DW_EH_PE_udata2: - result = readPointerHelper<uint16_t>(p); - break; - case DW_EH_PE_udata4: - result = readPointerHelper<uint32_t>(p); - break; - case DW_EH_PE_udata8: - result = readPointerHelper<uint64_t>(p); - break; - case DW_EH_PE_sdata2: - result = readPointerHelper<int16_t>(p); - break; - case DW_EH_PE_sdata4: - result = readPointerHelper<int32_t>(p); - break; - case DW_EH_PE_sdata8: - result = readPointerHelper<int64_t>(p); - break; - default: - // not supported - abort(); - break; - } - // then add relative offset - switch (encoding & 0x70) - { - case DW_EH_PE_absptr: - // do nothing - break; - case DW_EH_PE_pcrel: - if (result) - result += (uintptr_t)(*data); - break; - case DW_EH_PE_textrel: - case DW_EH_PE_datarel: - case DW_EH_PE_funcrel: - case DW_EH_PE_aligned: - default: - // not supported - abort(); - break; - } - // then apply indirection - if (result && (encoding & DW_EH_PE_indirect)) - result = *((uintptr_t*)result); - *data = p; - return result; -} - -static -void -call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) -{ - __cxa_begin_catch(unwind_exception); - if (native_exception) - { - // Use the stored terminate_handler if possible - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - std::__terminate(exception_header->terminateHandler); - } - std::terminate(); -} - -#if defined(_LIBCXXABI_ARM_EHABI) -static const void* read_target2_value(const void* ptr) -{ - uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr); - if (!offset) - return 0; - // "ARM EABI provides a TARGET2 relocation to describe these typeinfo - // pointers. The reason being it allows their precise semantics to be - // deferred to the linker. For bare-metal they turn into absolute - // relocations. For linux they turn into GOT-REL relocations." - // https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html -#if defined(LIBCXXABI_BAREMETAL) - return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(ptr) + - offset); -#else - return *reinterpret_cast<const void **>(reinterpret_cast<uintptr_t>(ptr) + - offset); -#endif -} - -static const __shim_type_info* -get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); - return reinterpret_cast<const __shim_type_info *>( - read_target2_value(ttypePtr)); -} -#else // !defined(_LIBCXXABI_ARM_EHABI) -static -const __shim_type_info* -get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, bool native_exception, - _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - switch (ttypeEncoding & 0x0F) - { - case DW_EH_PE_absptr: - ttypeIndex *= sizeof(void*); - break; - case DW_EH_PE_udata2: - case DW_EH_PE_sdata2: - ttypeIndex *= 2; - break; - case DW_EH_PE_udata4: - case DW_EH_PE_sdata4: - ttypeIndex *= 4; - break; - case DW_EH_PE_udata8: - case DW_EH_PE_sdata8: - ttypeIndex *= 8; - break; - default: - // this should not happen. Indicates corrupted eh_table. - call_terminate(native_exception, unwind_exception); - } - classInfo -= ttypeIndex; - return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); -} -#endif // !defined(_LIBCXXABI_ARM_EHABI) - -/* - This is checking a thrown exception type, excpType, against a possibly empty - list of catchType's which make up an exception spec. - - An exception spec acts like a catch handler, but in reverse. This "catch - handler" will catch an excpType if and only if none of the catchType's in - the list will catch a excpType. If any catchType in the list can catch an - excpType, then this exception spec does not catch the excpType. -*/ -#if defined(_LIBCXXABI_ARM_EHABI) -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - - assert(((ttypeEncoding == DW_EH_PE_absptr) || // LLVM or GCC 4.6 - (ttypeEncoding == DW_EH_PE_pcrel) || // GCC 4.7 baremetal - (ttypeEncoding == (DW_EH_PE_pcrel | DW_EH_PE_indirect))) && // GCC 4.7 linux - "Unexpected TTypeEncoding"); - (void)ttypeEncoding; - - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const void** temp = reinterpret_cast<const void**>( - reinterpret_cast<uintptr_t>(classInfo) + - static_cast<uintptr_t>(specIndex) * sizeof(uintptr_t)); - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - // ARM EHABI exception specification table (filter table) consists of - // several pointers which will directly point to the type info object - // (instead of ttypeIndex). The table will be terminated with 0. - const void** ttypePtr = temp++; - if (*ttypePtr == 0) - break; - // We can get the __shim_type_info simply by performing a - // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. - const __shim_type_info* catchType = - static_cast<const __shim_type_info*>(read_target2_value(ttypePtr)); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; -} -#else -static -bool -exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, - uint8_t ttypeEncoding, const __shim_type_info* excpType, - void* adjustedPtr, _Unwind_Exception* unwind_exception) -{ - if (classInfo == 0) - { - // this should not happen. Indicates corrupted eh_table. - call_terminate(false, unwind_exception); - } - // specIndex is negative of 1-based byte offset into classInfo; - specIndex = -specIndex; - --specIndex; - const uint8_t* temp = classInfo + specIndex; - // If any type in the spec list can catch excpType, return false, else return true - // adjustments to adjustedPtr are ignored. - while (true) - { - uint64_t ttypeIndex = readULEB128(&temp); - if (ttypeIndex == 0) - break; - const __shim_type_info* catchType = get_shim_type_info(ttypeIndex, - classInfo, - ttypeEncoding, - true, - unwind_exception); - void* tempPtr = adjustedPtr; - if (catchType->can_catch(excpType, tempPtr)) - return false; - } - return true; -} -#endif - -static -void* -get_thrown_object_ptr(_Unwind_Exception* unwind_exception) -{ - // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1 - // Regardless, this library is prohibited from touching a foreign exception - void* adjustedPtr = unwind_exception + 1; - if (__getExceptionClass(unwind_exception) == kOurDependentExceptionClass) - adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException; - return adjustedPtr; -} - -namespace -{ - -struct scan_results -{ - int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup - const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance. - const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected - uintptr_t landingPad; // null -> nothing found, else something found - void* adjustedPtr; // Used in cxa_exception.cpp - _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR, - // _URC_FATAL_PHASE2_ERROR, - // _URC_CONTINUE_UNWIND, - // _URC_HANDLER_FOUND -}; - -} // unnamed namespace - -static -void -set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, - const scan_results& results) -{ -#if defined(__USING_SJLJ_EXCEPTIONS__) -#define __builtin_eh_return_data_regno(regno) regno -#endif - _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), - reinterpret_cast<uintptr_t>(unwind_exception)); - _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), - static_cast<uintptr_t>(results.ttypeIndex)); - _Unwind_SetIP(context, results.landingPad); -} - -/* - There are 3 types of scans needed: - - 1. Scan for handler with native or foreign exception. If handler found, - save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. - May also report an error on invalid input. - May terminate for invalid exception table. - _UA_SEARCH_PHASE - - 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND, - or call terminate. - _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception - - 3. Scan for cleanups. If a handler is found and this isn't forced unwind, - then terminate, otherwise ignore the handler and keep looking for cleanup. - If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. - May also report an error on invalid input. - May terminate for invalid exception table. - _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME -*/ - -static void scan_eh_tab(scan_results &results, _Unwind_Action actions, - bool native_exception, - _Unwind_Exception *unwind_exception, - _Unwind_Context *context) { - // Initialize results to found nothing but an error - results.ttypeIndex = 0; - results.actionRecord = 0; - results.languageSpecificData = 0; - results.landingPad = 0; - results.adjustedPtr = 0; - results.reason = _URC_FATAL_PHASE1_ERROR; - // Check for consistent actions - if (actions & _UA_SEARCH_PHASE) - { - // Do Phase 1 - if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) - { - // None of these flags should be set during Phase 1 - // Client error - results.reason = _URC_FATAL_PHASE1_ERROR; - return; - } - } - else if (actions & _UA_CLEANUP_PHASE) - { - if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) - { - // _UA_HANDLER_FRAME should only be set if phase 1 found a handler. - // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened. - // Client error - results.reason = _URC_FATAL_PHASE2_ERROR; - return; - } - } - else // Neither _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set - { - // One of these should be set. - // Client error - results.reason = _URC_FATAL_PHASE1_ERROR; - return; - } - // Start scan by getting exception table address - const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context); - if (lsda == 0) - { - // There is no exception table - results.reason = _URC_CONTINUE_UNWIND; - return; - } - results.languageSpecificData = lsda; - // Get the current instruction pointer and offset it before next - // instruction in the current frame which threw the exception. - uintptr_t ip = _Unwind_GetIP(context) - 1; - // Get beginning current frame's code (as defined by the - // emitted dwarf code) - uintptr_t funcStart = _Unwind_GetRegionStart(context); -#ifdef __USING_SJLJ_EXCEPTIONS__ - if (ip == uintptr_t(-1)) - { - // no action - results.reason = _URC_CONTINUE_UNWIND; - return; - } - else if (ip == 0) - call_terminate(native_exception, unwind_exception); - // ip is 1-based index into call site table -#else // !__USING_SJLJ_EXCEPTIONS__ - uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) - const uint8_t* classInfo = NULL; - // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding - // dwarf emission - // Parse LSDA header. - uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); - if (lpStart == 0) - lpStart = (const uint8_t*)funcStart; - uint8_t ttypeEncoding = *lsda++; - if (ttypeEncoding != DW_EH_PE_omit) - { - // Calculate type info locations in emitted dwarf code which - // were flagged by type info arguments to llvm.eh.selector - // intrinsic - uintptr_t classInfoOffset = readULEB128(&lsda); - classInfo = lsda + classInfoOffset; - } - // Walk call-site table looking for range that - // includes current PC. - uint8_t callSiteEncoding = *lsda++; -#ifdef __USING_SJLJ_EXCEPTIONS__ - (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used -#endif - uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda)); - const uint8_t* callSiteTableStart = lsda; - const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; - const uint8_t* actionTableStart = callSiteTableEnd; - const uint8_t* callSitePtr = callSiteTableStart; - while (callSitePtr < callSiteTableEnd) - { - // There is one entry per call site. -#ifndef __USING_SJLJ_EXCEPTIONS__ - // The call sites are non-overlapping in [start, start+length) - // The call sites are ordered in increasing value of start - uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); - uintptr_t actionEntry = readULEB128(&callSitePtr); - if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __USING_SJLJ_EXCEPTIONS__ - // ip is 1-based index into this table - uintptr_t landingPad = readULEB128(&callSitePtr); - uintptr_t actionEntry = readULEB128(&callSitePtr); - if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ - { - // Found the call site containing ip. -#ifndef __USING_SJLJ_EXCEPTIONS__ - if (landingPad == 0) - { - // No handler here - results.reason = _URC_CONTINUE_UNWIND; - return; - } - landingPad = (uintptr_t)lpStart + landingPad; -#else // __USING_SJLJ_EXCEPTIONS__ - ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ - if (actionEntry == 0) - { - // Found a cleanup - // If this is a type 1 or type 2 search, there are no handlers - // If this is a type 3 search, you want to install the cleanup. - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - results.ttypeIndex = 0; // Redundant but clarifying - results.landingPad = landingPad; - results.reason = _URC_HANDLER_FOUND; - return; - } - // No handler here - results.reason = _URC_CONTINUE_UNWIND; - return; - } - // Convert 1-based byte offset into - const uint8_t* action = actionTableStart + (actionEntry - 1); - // Scan action entries until you find a matching handler, cleanup, or the end of action list - while (true) - { - const uint8_t* actionRecord = action; - int64_t ttypeIndex = readSLEB128(&action); - if (ttypeIndex > 0) - { - // Found a catch, does it actually catch? - // First check for catch (...) - const __shim_type_info* catchType = - get_shim_type_info(static_cast<uint64_t>(ttypeIndex), - classInfo, ttypeEncoding, - native_exception, unwind_exception); - if (catchType == 0) - { - // Found catch (...) catches everything, including foreign exceptions - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 2 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - // Else this is a catch (T) clause and will never - // catch a foreign exception - else if (native_exception) - { - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - void* adjustedPtr = get_thrown_object_ptr(unwind_exception); - const __shim_type_info* excpType = - static_cast<const __shim_type_info*>(exception_header->exceptionType); - if (adjustedPtr == 0 || excpType == 0) - { - // Something very bad happened - call_terminate(native_exception, unwind_exception); - } - if (catchType->can_catch(excpType, adjustedPtr)) - { - // Found a matching handler - // If this is a type 1 search save state and return _URC_HANDLER_FOUND - // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - } - // Scan next action ... - } - else if (ttypeIndex < 0) - { - // Found an exception spec. If this is a foreign exception, - // it is always caught. - if (native_exception) - { - // Does the exception spec catch this native exception? - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - void* adjustedPtr = get_thrown_object_ptr(unwind_exception); - const __shim_type_info* excpType = - static_cast<const __shim_type_info*>(exception_header->exceptionType); - if (adjustedPtr == 0 || excpType == 0) - { - // Something very bad happened - call_terminate(native_exception, unwind_exception); - } - if (exception_spec_can_catch(ttypeIndex, classInfo, - ttypeEncoding, excpType, - adjustedPtr, unwind_exception)) - { - // native exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if (actions & _UA_SEARCH_PHASE) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = adjustedPtr; - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - } - else - { - // foreign exception caught by exception spec - // If this is a type 1 search, save state and return _URC_HANDLER_FOUND - // If this is a type 2 search, save state and return _URC_HANDLER_FOUND - // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! - // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan - if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - else if (!(actions & _UA_FORCE_UNWIND)) - { - // It looks like the exception table has changed - // on us. Likely stack corruption! - call_terminate(native_exception, unwind_exception); - } - } - // Scan next action ... - } - else // ttypeIndex == 0 - { - // Found a cleanup - // If this is a type 1 search, ignore it and continue scan - // If this is a type 2 search, ignore it and continue scan - // If this is a type 3 search, save state and return _URC_HANDLER_FOUND - if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) - { - // Save state and return _URC_HANDLER_FOUND - results.ttypeIndex = ttypeIndex; - results.actionRecord = actionRecord; - results.landingPad = landingPad; - results.adjustedPtr = get_thrown_object_ptr(unwind_exception); - results.reason = _URC_HANDLER_FOUND; - return; - } - } - const uint8_t* temp = action; - int64_t actionOffset = readSLEB128(&temp); - if (actionOffset == 0) - { - // End of action list, no matching handler or cleanup found - results.reason = _URC_CONTINUE_UNWIND; - return; - } - // Go to next action - action += actionOffset; - } // there is no break out of this loop, only return - } -#ifndef __USING_SJLJ_EXCEPTIONS__ - else if (ipOffset < start) - { - // There is no call site for this ip - // Something bad has happened. We should never get here. - // Possible stack corruption. - call_terminate(native_exception, unwind_exception); - } -#endif // !__USING_SJLJ_EXCEPTIONS__ - } // there might be some tricky cases which break out of this loop - - // It is possible that no eh table entry specify how to handle - // this exception. By spec, terminate it immediately. - call_terminate(native_exception, unwind_exception); -} - -// public API - -/* -The personality function branches on actions like so: - -_UA_SEARCH_PHASE - - If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's - an error from above, return _URC_FATAL_PHASE1_ERROR. - - Scan for anything that could stop unwinding: - - 1. A catch clause that will catch this exception - (will never catch foreign). - 2. A catch (...) (will always catch foreign). - 3. An exception spec that will catch this exception - (will always catch foreign). - If a handler is found - If not foreign - Save state in header - return _URC_HANDLER_FOUND - Else a handler not found - return _URC_CONTINUE_UNWIND - -_UA_CLEANUP_PHASE - - If _UA_HANDLER_FRAME - If _UA_FORCE_UNWIND - How did this happen? return _URC_FATAL_PHASE2_ERROR - If foreign - Do _UA_SEARCH_PHASE to recover state - else - Recover state from header - Transfer control to landing pad. return _URC_INSTALL_CONTEXT - - Else - - This branch handles both normal C++ non-catching handlers (cleanups) - and forced unwinding. - Scan for anything that can not stop unwinding: - - 1. A cleanup. - - If a cleanup is found - transfer control to it. return _URC_INSTALL_CONTEXT - Else a cleanup is not found: return _URC_CONTINUE_UNWIND -*/ - -#if !defined(_LIBCXXABI_ARM_EHABI) -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -static _Unwind_Reason_Code __gxx_personality_imp -#else -_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code -#ifdef __USING_SJLJ_EXCEPTIONS__ -__gxx_personality_sj0 -#else -__gxx_personality_v0 -#endif -#endif - (int version, _Unwind_Action actions, uint64_t exceptionClass, - _Unwind_Exception* unwind_exception, _Unwind_Context* context) -{ - if (version != 1 || unwind_exception == 0 || context == 0) - return _URC_FATAL_PHASE1_ERROR; - - bool native_exception = (exceptionClass & get_vendor_and_language) == - (kOurExceptionClass & get_vendor_and_language); - scan_results results; - if (actions & _UA_SEARCH_PHASE) - { - // Phase 1 search: All we're looking for in phase 1 is a handler that - // halts unwinding - scan_eh_tab(results, actions, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - // Found one. Can we cache the results somewhere to optimize phase 2? - if (native_exception) - { - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex); - exception_header->actionRecord = results.actionRecord; - exception_header->languageSpecificData = results.languageSpecificData; - exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad); - exception_header->adjustedPtr = results.adjustedPtr; - } - return _URC_HANDLER_FOUND; - } - // Did not find a catching-handler. Return the results of the scan - // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR - // if we were called improperly). - return results.reason; - } - if (actions & _UA_CLEANUP_PHASE) - { - // Phase 2 search: - // Did we find a catching handler in phase 1? - if (actions & _UA_HANDLER_FRAME) - { - // Yes, phase 1 said we have a catching handler here. - // Did we cache the results of the scan? - if (native_exception) - { - // Yes, reload the results from the cache. - __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - results.ttypeIndex = exception_header->handlerSwitchValue; - results.actionRecord = exception_header->actionRecord; - results.languageSpecificData = exception_header->languageSpecificData; - results.landingPad = reinterpret_cast<uintptr_t>(exception_header->catchTemp); - results.adjustedPtr = exception_header->adjustedPtr; - } - else - { - // No, do the scan again to reload the results. - scan_eh_tab(results, actions, native_exception, unwind_exception, context); - // Phase 1 told us we would find a handler. Now in Phase 2 we - // didn't find a handler. The eh table should not be changing! - if (results.reason != _URC_HANDLER_FOUND) - call_terminate(native_exception, unwind_exception); - } - // Jump to the handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - // Either we didn't do a phase 1 search (due to forced unwinding), or - // phase 1 reported no catching-handlers. - // Search for a (non-catching) cleanup - scan_eh_tab(results, actions, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - // Found a non-catching handler. Jump to it: - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - // Did not find a cleanup. Return the results of the scan - // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR - // if we were called improperly). - return results.reason; - } - // We were called improperly: neither a phase 1 or phase 2 search - return _URC_FATAL_PHASE1_ERROR; -} - -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -extern "C" _LIBCXXABI_FUNC_VIS EXCEPTION_DISPOSITION -__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame, - PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) -{ - return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp, - __gxx_personality_imp); -} -#endif - -#else - -extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, - _Unwind_Context*); - -// Helper function to unwind one frame. -// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the -// personality routine should update the virtual register set (VRS) according to the -// corresponding frame unwinding instructions (ARM EHABI 9.3.) -static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, - _Unwind_Context* context) -{ - if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK) - return _URC_FAILURE; - return _URC_CONTINUE_UNWIND; -} - -// ARM register names -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) -static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block -#endif -static const uint32_t REG_SP = 13; - -static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception, - const scan_results& results) -{ - unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr; - unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord; - unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData; - unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad; - unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex; -} - -static void load_results_from_barrier_cache(scan_results& results, - const _Unwind_Exception* unwind_exception) -{ - results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0]; - results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1]; - results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; - results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3]; - results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; -} - -extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code -__gxx_personality_v0(_Unwind_State state, - _Unwind_Exception* unwind_exception, - _Unwind_Context* context) -{ - if (unwind_exception == 0 || context == 0) - return _URC_FATAL_PHASE1_ERROR; - - bool native_exception = __isOurExceptionClass(unwind_exception); - -#if !defined(LIBCXXABI_USE_LLVM_UNWINDER) - // Copy the address of _Unwind_Control_Block to r12 so that - // _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can - // return correct address. - _Unwind_SetGR(context, REG_UCB, reinterpret_cast<uint32_t>(unwind_exception)); -#endif - - // Check the undocumented force unwinding behavior - bool is_force_unwinding = state & _US_FORCE_UNWIND; - state &= ~_US_FORCE_UNWIND; - - scan_results results; - switch (state) { - case _US_VIRTUAL_UNWIND_FRAME: - if (is_force_unwinding) - return continue_unwind(unwind_exception, context); - - // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding - scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP); - if (native_exception) - save_results_to_barrier_cache(unwind_exception, results); - return _URC_HANDLER_FOUND; - } - // Did not find the catch handler - if (results.reason == _URC_CONTINUE_UNWIND) - return continue_unwind(unwind_exception, context); - return results.reason; - - case _US_UNWIND_FRAME_STARTING: - // TODO: Support force unwinding in the phase 2 search. - // NOTE: In order to call the cleanup functions, _Unwind_ForcedUnwind() - // will call this personality function with (_US_FORCE_UNWIND | - // _US_UNWIND_FRAME_STARTING). - - // Phase 2 search - if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP)) - { - // Found a catching handler in phase 1 - if (native_exception) - { - // Load the result from the native exception barrier cache. - load_results_from_barrier_cache(results, unwind_exception); - results.reason = _URC_HANDLER_FOUND; - } - else - { - // Search for the catching handler again for the foreign exception. - scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME), - native_exception, unwind_exception, context); - if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one - call_terminate(native_exception, unwind_exception); - } - - // Install the context for the catching handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - - // Either we didn't do a phase 1 search (due to forced unwinding), or - // phase 1 reported no catching-handlers. - // Search for a (non-catching) cleanup - scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context); - if (results.reason == _URC_HANDLER_FOUND) - { - // Found a non-catching handler - - // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some - // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from - // __cxa_get_globals(). - __cxa_begin_cleanup(unwind_exception); - - // Install the context for the cleanup handler - set_registers(unwind_exception, context, results); - return _URC_INSTALL_CONTEXT; - } - - // Did not find any handler - if (results.reason == _URC_CONTINUE_UNWIND) - return continue_unwind(unwind_exception, context); - return results.reason; - - case _US_UNWIND_FRAME_RESUME: - return continue_unwind(unwind_exception, context); - } - - // We were called improperly: neither a phase 1 or phase 2 search - return _URC_FATAL_PHASE1_ERROR; -} -#endif - - -__attribute__((noreturn)) -_LIBCXXABI_FUNC_VIS void -__cxa_call_unexpected(void* arg) -{ - _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); - if (unwind_exception == 0) - call_terminate(false, unwind_exception); - __cxa_begin_catch(unwind_exception); - bool native_old_exception = __isOurExceptionClass(unwind_exception); - std::unexpected_handler u_handler; - std::terminate_handler t_handler; - __cxa_exception* old_exception_header = 0; - int64_t ttypeIndex; - const uint8_t* lsda; - if (native_old_exception) - { - old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; - t_handler = old_exception_header->terminateHandler; - u_handler = old_exception_header->unexpectedHandler; - // If std::__unexpected(u_handler) rethrows the same exception, - // these values get overwritten by the rethrow. So save them now: -#if defined(_LIBCXXABI_ARM_EHABI) - ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; - lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; -#else - ttypeIndex = old_exception_header->handlerSwitchValue; - lsda = old_exception_header->languageSpecificData; -#endif - } - else - { - t_handler = std::get_terminate(); - u_handler = std::get_unexpected(); - } - try - { - std::__unexpected(u_handler); - } - catch (...) - { - // If the old exception is foreign, then all we can do is terminate. - // We have no way to recover the needed old exception spec. There's - // no way to pass that information here. And the personality routine - // can't call us directly and do anything but terminate() if we throw - // from here. - if (native_old_exception) - { - // Have: - // old_exception_header->languageSpecificData - // old_exception_header->actionRecord - // Need - // const uint8_t* classInfo - // uint8_t ttypeEncoding - uint8_t lpStartEncoding = *lsda++; - const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); - (void)lpStart; // purposefully unused. Just needed to increment lsda. - uint8_t ttypeEncoding = *lsda++; - if (ttypeEncoding == DW_EH_PE_omit) - std::__terminate(t_handler); - uintptr_t classInfoOffset = readULEB128(&lsda); - const uint8_t* classInfo = lsda + classInfoOffset; - // Is this new exception catchable by the exception spec at ttypeIndex? - // The answer is obviously yes if the new and old exceptions are the same exception - // If no - // throw; - __cxa_eh_globals* globals = __cxa_get_globals_fast(); - __cxa_exception* new_exception_header = globals->caughtExceptions; - if (new_exception_header == 0) - // This shouldn't be able to happen! - std::__terminate(t_handler); - bool native_new_exception = __isOurExceptionClass(&new_exception_header->unwindHeader); - void* adjustedPtr; - if (native_new_exception && (new_exception_header != old_exception_header)) - { - const __shim_type_info* excpType = - static_cast<const __shim_type_info*>(new_exception_header->exceptionType); - adjustedPtr = - __getExceptionClass(&new_exception_header->unwindHeader) == kOurDependentExceptionClass ? - ((__cxa_dependent_exception*)new_exception_header)->primaryException : - new_exception_header + 1; - if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch, but for the old exception, - // not the new one. This is a little tricky ... - // Disguise new_exception_header as a rethrown exception, but - // don't actually rethrow it. This means you can temporarily - // end the catch clause enclosing new_exception_header without - // __cxa_end_catch destroying new_exception_header. - new_exception_header->handlerCount = -new_exception_header->handlerCount; - globals->uncaughtExceptions += 1; - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Call __cxa_end_catch for old_exception_header - __cxa_end_catch(); - // Renter this catch clause with new_exception_header - __cxa_begin_catch(&new_exception_header->unwindHeader); - // Rethrow new_exception_header - throw; - } - } - // Will a std::bad_exception be catchable by the exception spec at - // ttypeIndex? - // If no - // throw std::bad_exception(); - const __shim_type_info* excpType = - static_cast<const __shim_type_info*>(&typeid(std::bad_exception)); - std::bad_exception be; - adjustedPtr = &be; - if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, - excpType, adjustedPtr, unwind_exception)) - { - // We need to __cxa_end_catch for both the old exception and the - // new exception. Technically we should do it in that order. - // But it is expedient to do it in the opposite order: - // Call __cxa_end_catch for new_exception_header - __cxa_end_catch(); - // Throw std::bad_exception will __cxa_end_catch for - // old_exception_header - throw be; - } - } - } - std::__terminate(t_handler); -} - -} // extern "C" - -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_thread_atexit.cpp b/lib/libcxxabi/src/cxa_thread_atexit.cpp deleted file mode 100644 index 49d15d6b145..00000000000 --- a/lib/libcxxabi/src/cxa_thread_atexit.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//===----------------------- cxa_thread_atexit.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 "abort_message.h" -#include "cxxabi.h" -#include <__threading_support> -#include <cstdlib> - -namespace __cxxabiv1 { - - using Dtor = void(*)(void*); - - extern "C" -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL - // A weak symbol is used to detect this function's presence in the C library - // at runtime, even if libc++ is built against an older libc - _LIBCXXABI_WEAK -#endif - int __cxa_thread_atexit_impl(Dtor, void*, void*); - -#ifndef HAVE___CXA_THREAD_ATEXIT_IMPL - -namespace { - // This implementation is used if the C library does not provide - // __cxa_thread_atexit_impl() for us. It has a number of limitations that are - // difficult to impossible to address without ..._impl(): - // - // - dso_symbol is ignored. This means that a shared library may be unloaded - // (via dlclose()) before its thread_local destructors have run. - // - // - thread_local destructors for the main thread are run by the destructor of - // a static object. This is later than expected; they should run before the - // destructors of any objects with static storage duration. - // - // - thread_local destructors on non-main threads run on the first iteration - // through the __libccpp_tls_key destructors. - // std::notify_all_at_thread_exit() and similar functions must be careful to - // wait until the second iteration to provide their intended ordering - // guarantees. - // - // Another limitation, though one shared with ..._impl(), is that any - // thread_locals that are first initialized after non-thread_local global - // destructors begin to run will not be destroyed. [basic.start.term] states - // that all thread_local destructors are sequenced before the destruction of - // objects with static storage duration, resulting in a contradiction if a - // thread_local is constructed after that point. Thus we consider such - // programs ill-formed, and don't bother to run those destructors. (If the - // program terminates abnormally after such a thread_local is constructed, - // the destructor is not expected to run and thus there is no contradiction. - // So construction still has to work.) - - struct DtorList { - Dtor dtor; - void* obj; - DtorList* next; - }; - - // The linked list of thread-local destructors to run - __thread DtorList* dtors = nullptr; - // True if the destructors are currently scheduled to run on this thread - __thread bool dtors_alive = false; - // Used to trigger destructors on thread exit; value is ignored - std::__libcpp_tls_key dtors_key; - - void run_dtors(void*) { - while (auto head = dtors) { - dtors = head->next; - head->dtor(head->obj); - std::free(head); - } - - dtors_alive = false; - } - - struct DtorsManager { - DtorsManager() { - // There is intentionally no matching std::__libcpp_tls_delete call, as - // __cxa_thread_atexit() may be called arbitrarily late (for example, from - // global destructors or atexit() handlers). - if (std::__libcpp_tls_create(&dtors_key, run_dtors) != 0) { - abort_message("std::__libcpp_tls_create() failed in __cxa_thread_atexit()"); - } - } - - ~DtorsManager() { - // std::__libcpp_tls_key destructors do not run on threads that call exit() - // (including when the main thread returns from main()), so we explicitly - // call the destructor here. This runs at exit time (potentially earlier - // if libc++abi is dlclose()'d). Any thread_locals initialized after this - // point will not be destroyed. - run_dtors(nullptr); - } - }; -} // namespace - -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL - -extern "C" { - - _LIBCXXABI_FUNC_VIS int __cxa_thread_atexit(Dtor dtor, void* obj, void* dso_symbol) throw() { -#ifdef HAVE___CXA_THREAD_ATEXIT_IMPL - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); -#else - if (__cxa_thread_atexit_impl) { - return __cxa_thread_atexit_impl(dtor, obj, dso_symbol); - } else { - // Initialize the dtors std::__libcpp_tls_key (uses __cxa_guard_*() for - // one-time initialization and __cxa_atexit() for destruction) - static DtorsManager manager; - - if (!dtors_alive) { - if (std::__libcpp_tls_set(dtors_key, &dtors_key) != 0) { - return -1; - } - dtors_alive = true; - } - - auto head = static_cast<DtorList*>(std::malloc(sizeof(DtorList))); - if (!head) { - return -1; - } - - head->dtor = dtor; - head->obj = obj; - head->next = dtors; - dtors = head; - - return 0; - } -#endif // HAVE___CXA_THREAD_ATEXIT_IMPL - } - -} // extern "C" -} // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/cxa_unexpected.cpp b/lib/libcxxabi/src/cxa_unexpected.cpp deleted file mode 100644 index 7d4ef80c39e..00000000000 --- a/lib/libcxxabi/src/cxa_unexpected.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//===------------------------- cxa_unexpected.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 <exception> -#include "cxxabi.h" -#include "cxa_exception.hpp" - -namespace __cxxabiv1 -{ - -extern "C" -{ - -} - -} // namespace __cxxabiv1 - diff --git a/lib/libcxxabi/src/cxa_vector.cpp b/lib/libcxxabi/src/cxa_vector.cpp deleted file mode 100644 index c32a2119756..00000000000 --- a/lib/libcxxabi/src/cxa_vector.cpp +++ /dev/null @@ -1,367 +0,0 @@ -//===-------------------------- cxa_vector.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 "Array Construction and Destruction APIs" -// http://mentorembedded.github.io/cxx-abi/abi.html#array-ctor -// -//===----------------------------------------------------------------------===// - -#include "cxxabi.h" - -#include <exception> // for std::terminate - -namespace __cxxabiv1 { - -#if 0 -#pragma mark --Helper routines and classes -- -#endif - -namespace { - inline static size_t __get_element_count ( void *p ) { - return static_cast <size_t *> (p)[-1]; - } - - inline static void __set_element_count ( void *p, size_t element_count ) { - static_cast <size_t *> (p)[-1] = element_count; - } - - -// A pair of classes to simplify exception handling and control flow. -// They get passed a block of memory in the constructor, and unless the -// 'release' method is called, they deallocate the memory in the destructor. -// Preferred usage is to allocate some memory, attach it to one of these objects, -// and then, when all the operations to set up the memory block have succeeded, -// call 'release'. If any of the setup operations fail, or an exception is -// thrown, then the block is automatically deallocated. -// -// The only difference between these two classes is the signature for the -// deallocation function (to match new2/new3 and delete2/delete3. - class st_heap_block2 { - public: - typedef void (*dealloc_f)(void *); - - st_heap_block2 ( dealloc_f dealloc, void *ptr ) - : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {} - ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; } - void release () { enabled_ = false; } - - private: - dealloc_f dealloc_; - void *ptr_; - bool enabled_; - }; - - class st_heap_block3 { - public: - typedef void (*dealloc_f)(void *, size_t); - - st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size ) - : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {} - ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; } - void release () { enabled_ = false; } - - private: - dealloc_f dealloc_; - void *ptr_; - size_t size_; - bool enabled_; - }; - - class st_cxa_cleanup { - public: - typedef void (*destruct_f)(void *); - - st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor ) - : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ), - destructor_ ( destructor ), enabled_ ( true ) {} - ~st_cxa_cleanup () { - if ( enabled_ ) - __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ ); - } - - void release () { enabled_ = false; } - - private: - void *ptr_; - size_t &idx_; - size_t element_size_; - destruct_f destructor_; - bool enabled_; - }; - - class st_terminate { - public: - st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {} - ~st_terminate () { if ( enabled_ ) std::terminate (); } - void release () { enabled_ = false; } - private: - bool enabled_ ; - }; -} - -#if 0 -#pragma mark --Externally visible routines-- -#endif - -extern "C" { - -// Equivalent to -// -// __cxa_vec_new2(element_count, element_size, padding_size, constructor, -// destructor, &::operator new[], &::operator delete[]) -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *)) { - return __cxa_vec_new2 ( element_count, element_size, padding_size, - constructor, destructor, &::operator new [], &::operator delete [] ); -} - - - -// Given the number and size of elements for an array and the non-negative -// size of prefix padding for a cookie, allocate space (using alloc) for -// the array preceded by the specified padding, initialize the cookie if -// the padding is non-zero, and call the given constructor on each element. -// Return the address of the array proper, after the padding. -// -// If alloc throws an exception, rethrow the exception. If alloc returns -// NULL, return NULL. If the constructor throws an exception, call -// destructor for any already constructed elements, and rethrow the -// exception. If the destructor throws an exception, call std::terminate. -// -// The constructor may be NULL, in which case it must not be called. If the -// padding_size is zero, the destructor may be NULL; in that case it must -// not be called. -// -// Neither alloc nor dealloc may be NULL. -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new2(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *)) { - const size_t heap_size = element_count * element_size + padding_size; - char * const heap_block = static_cast<char *> ( alloc ( heap_size )); - char *vec_base = heap_block; - - if ( NULL != vec_base ) { - st_heap_block2 heap ( dealloc, heap_block ); - - // put the padding before the array elements - if ( 0 != padding_size ) { - vec_base += padding_size; - __set_element_count ( vec_base, element_count ); - } - - // Construct the elements - __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); - heap.release (); // We're good! - } - - return vec_base; -} - - -// Same as __cxa_vec_new2 except that the deallocation function takes both -// the object address and its size. -_LIBCXXABI_FUNC_VIS void * -__cxa_vec_new3(size_t element_count, size_t element_size, size_t padding_size, - void (*constructor)(void *), void (*destructor)(void *), - void *(*alloc)(size_t), void (*dealloc)(void *, size_t)) { - const size_t heap_size = element_count * element_size + padding_size; - char * const heap_block = static_cast<char *> ( alloc ( heap_size )); - char *vec_base = heap_block; - - if ( NULL != vec_base ) { - st_heap_block3 heap ( dealloc, heap_block, heap_size ); - - // put the padding before the array elements - if ( 0 != padding_size ) { - vec_base += padding_size; - __set_element_count ( vec_base, element_count ); - } - - // Construct the elements - __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); - heap.release (); // We're good! - } - - return vec_base; -} - - -// Given the (data) addresses of a destination and a source array, an -// element count and an element size, call the given copy constructor to -// copy each element from the source array to the destination array. The -// copy constructor's arguments are the destination address and source -// address, respectively. If an exception occurs, call the given destructor -// (if non-NULL) on each copied element and rethrow. If the destructor -// throws an exception, call terminate(). The constructor and or destructor -// pointers may be NULL. If either is NULL, no action is taken when it -// would have been called. - -_LIBCXXABI_FUNC_VIS void __cxa_vec_cctor(void *dest_array, void *src_array, - size_t element_count, - size_t element_size, - void (*constructor)(void *, void *), - void (*destructor)(void *)) { - if ( NULL != constructor ) { - size_t idx = 0; - char *src_ptr = static_cast<char *>(src_array); - char *dest_ptr = static_cast<char *>(dest_array); - st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor ); - - for ( idx = 0; idx < element_count; - ++idx, src_ptr += element_size, dest_ptr += element_size ) - constructor ( dest_ptr, src_ptr ); - cleanup.release (); // We're good! - } -} - - -// Given the (data) address of an array, not including any cookie padding, -// and the number and size of its elements, call the given constructor on -// each element. If the constructor throws an exception, call the given -// destructor for any already-constructed elements, and rethrow the -// exception. If the destructor throws an exception, call terminate(). The -// constructor and/or destructor pointers may be NULL. If either is NULL, -// no action is taken when it would have been called. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_ctor(void *array_address, size_t element_count, size_t element_size, - void (*constructor)(void *), void (*destructor)(void *)) { - if ( NULL != constructor ) { - size_t idx; - char *ptr = static_cast <char *> ( array_address ); - st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); - - // Construct the elements - for ( idx = 0; idx < element_count; ++idx, ptr += element_size ) - constructor ( ptr ); - cleanup.release (); // We're good! - } -} - -// Given the (data) address of an array, the number of elements, and the -// size of its elements, call the given destructor on each element. If the -// destructor throws an exception, rethrow after destroying the remaining -// elements if possible. If the destructor throws a second exception, call -// terminate(). The destructor pointer may be NULL, in which case this -// routine does nothing. -_LIBCXXABI_FUNC_VIS void __cxa_vec_dtor(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)) { - if ( NULL != destructor ) { - char *ptr = static_cast <char *> (array_address); - size_t idx = element_count; - st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); - { - st_terminate exception_guard (__cxa_uncaught_exception ()); - ptr += element_count * element_size; // one past the last element - - while ( idx-- > 0 ) { - ptr -= element_size; - destructor ( ptr ); - } - exception_guard.release (); // We're good ! - } - cleanup.release (); // We're still good! - } -} - -// Given the (data) address of an array, the number of elements, and the -// size of its elements, call the given destructor on each element. If the -// destructor throws an exception, call terminate(). The destructor pointer -// may be NULL, in which case this routine does nothing. -_LIBCXXABI_FUNC_VIS void __cxa_vec_cleanup(void *array_address, - size_t element_count, - size_t element_size, - void (*destructor)(void *)) { - if ( NULL != destructor ) { - char *ptr = static_cast <char *> (array_address); - size_t idx = element_count; - st_terminate exception_guard; - - ptr += element_count * element_size; // one past the last element - while ( idx-- > 0 ) { - ptr -= element_size; - destructor ( ptr ); - } - exception_guard.release (); // We're done! - } -} - - -// If the array_address is NULL, return immediately. Otherwise, given the -// (data) address of an array, the non-negative size of prefix padding for -// the cookie, and the size of its elements, call the given destructor on -// each element, using the cookie to determine the number of elements, and -// then delete the space by calling ::operator delete[](void *). If the -// destructor throws an exception, rethrow after (a) destroying the -// remaining elements, and (b) deallocating the storage. If the destructor -// throws a second exception, call terminate(). If padding_size is 0, the -// destructor pointer must be NULL. If the destructor pointer is NULL, no -// destructor call is to be made. -// -// The intent of this function is to permit an implementation to call this -// function when confronted with an expression of the form delete[] p in -// the source code, provided that the default deallocation function can be -// used. Therefore, the semantics of this function are consistent with -// those required by the standard. The requirement that the deallocation -// function be called even if the destructor throws an exception derives -// from the resolution to DR 353 to the C++ standard, which was adopted in -// April, 2003. -_LIBCXXABI_FUNC_VIS void __cxa_vec_delete(void *array_address, - size_t element_size, - size_t padding_size, - void (*destructor)(void *)) { - __cxa_vec_delete2 ( array_address, element_size, padding_size, - destructor, &::operator delete [] ); -} - -// Same as __cxa_vec_delete, except that the given function is used for -// deallocation instead of the default delete function. If dealloc throws -// an exception, the result is undefined. The dealloc pointer may not be -// NULL. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_delete2(void *array_address, size_t element_size, size_t padding_size, - void (*destructor)(void *), void (*dealloc)(void *)) { - if ( NULL != array_address ) { - char *vec_base = static_cast <char *> (array_address); - char *heap_block = vec_base - padding_size; - st_heap_block2 heap ( dealloc, heap_block ); - - if ( 0 != padding_size && NULL != destructor ) // call the destructors - __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ), - element_size, destructor ); - } -} - - -// Same as __cxa_vec_delete, except that the given function is used for -// deallocation instead of the default delete function. The deallocation -// function takes both the object address and its size. If dealloc throws -// an exception, the result is undefined. The dealloc pointer may not be -// NULL. -_LIBCXXABI_FUNC_VIS void -__cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size, - void (*destructor)(void *), void (*dealloc)(void *, size_t)) { - if ( NULL != array_address ) { - char *vec_base = static_cast <char *> (array_address); - char *heap_block = vec_base - padding_size; - const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0; - const size_t heap_block_size = element_size * element_count + padding_size; - st_heap_block3 heap ( dealloc, heap_block, heap_block_size ); - - if ( 0 != padding_size && NULL != destructor ) // call the destructors - __cxa_vec_dtor ( array_address, element_count, element_size, destructor ); - } -} - - -} // extern "C" - -} // abi diff --git a/lib/libcxxabi/src/cxa_virtual.cpp b/lib/libcxxabi/src/cxa_virtual.cpp deleted file mode 100644 index f59fa7ee2c6..00000000000 --- a/lib/libcxxabi/src/cxa_virtual.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===-------------------------- cxa_virtual.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 "cxxabi.h" -#include "abort_message.h" - -namespace __cxxabiv1 { -extern "C" { -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN -void __cxa_pure_virtual(void) { - abort_message("Pure virtual function called!"); -} - -_LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN -void __cxa_deleted_virtual(void) { - abort_message("Deleted virtual function called!"); -} -} // extern "C" -} // abi diff --git a/lib/libcxxabi/src/demangle/Compiler.h b/lib/libcxxabi/src/demangle/Compiler.h deleted file mode 100644 index e5f3c72a451..00000000000 --- a/lib/libcxxabi/src/demangle/Compiler.h +++ /dev/null @@ -1,34 +0,0 @@ -//===--- Compiler.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// This file is contains a subset of macros copied from -// llvm/lib/Demangle/Compiler.h. -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_COMPILER_H -#define LIBCXX_DEMANGLE_COMPILER_H - -#ifdef _MSC_VER -// snprintf is implemented in VS 2015 -#if _MSC_VER < 1900 -#define snprintf _snprintf_s -#endif -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#ifndef NDEBUG -#if __has_attribute(noinline) && __has_attribute(used) -#define DUMP_METHOD __attribute__((noinline, used)) -#else -#define DUMP_METHOD -#endif -#endif - -#endif diff --git a/lib/libcxxabi/src/demangle/ItaniumDemangle.h b/lib/libcxxabi/src/demangle/ItaniumDemangle.h deleted file mode 100644 index 9e9d183da7c..00000000000 --- a/lib/libcxxabi/src/demangle/ItaniumDemangle.h +++ /dev/null @@ -1,5189 +0,0 @@ -//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// -// -// 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. -// -//===----------------------------------------------------------------------===// -// -// WARNING: This file defines its contents within an anonymous namespace. It -// should not be included anywhere other than cxa_demangle.h. -// -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H -#define LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H - -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - -#include "Compiler.h" -#include "StringView.h" -#include "Utility.h" - -#include <cassert> -#include <cctype> -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <numeric> -#include <utility> - -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(BoolExpr) \ - X(IntegerCastExpr) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - -namespace { -namespace itanium_demangle { -// Base class of all AST nodes. The AST is built by the parser, then is -// traversed by the printLeft/Right functions to produce a demangled string. -class Node { -public: - enum Kind : unsigned char { -#define ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR - }; - - /// Three-way bool to track a cached value. Unknown is possible if this node - /// has an unexpanded parameter pack below it that may affect this cache. - enum class Cache : unsigned char { Yes, No, Unknown, }; - -private: - Kind K; - - // FIXME: Make these protected. -public: - /// Tracks if this node has a component on its right side, in which case we - /// need to call printRight. - Cache RHSComponentCache; - - /// Track if this node is a (possibly qualified) array type. This can affect - /// how we format the output string. - Cache ArrayCache; - - /// Track if this node is a (possibly qualified) function type. This can - /// affect how we format the output string. - Cache FunctionCache; - -public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} - - /// Visit the most-derived object corresponding to this object. - template<typename Fn> void visit(Fn F) const; - - // The following function is provided by all derived classes: - // - // Call F with arguments that, when passed to the constructor of this node, - // would construct an equivalent node. - //template<typename Fn> void match(Fn F) const; - - bool hasRHSComponent(OutputStream &S) const { - if (RHSComponentCache != Cache::Unknown) - return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); - } - - bool hasArray(OutputStream &S) const { - if (ArrayCache != Cache::Unknown) - return ArrayCache == Cache::Yes; - return hasArraySlow(S); - } - - bool hasFunction(OutputStream &S) const { - if (FunctionCache != Cache::Unknown) - return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); - } - - Kind getKind() const { return K; } - - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } - - // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to - // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } - - void print(OutputStream &S) const { - printLeft(S); - if (RHSComponentCache != Cache::No) - printRight(S); - } - - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; - - // Print the "right". This distinction is necessary to represent C++ types - // that appear on the RHS of their subtype, such as arrays or functions. - // Since most types don't have such a component, provide a default - // implementation. - virtual void printRight(OutputStream &) const {} - - virtual StringView getBaseName() const { return StringView(); } - - // Silence compiler warnings, this dtor will never be called. - virtual ~Node() = default; - -#ifndef NDEBUG - DUMP_METHOD void dump() const; -#endif -}; - -class NodeArray { - Node **Elements; - size_t NumElements; - -public: - NodeArray() : Elements(nullptr), NumElements(0) {} - NodeArray(Node **Elements_, size_t NumElements_) - : Elements(Elements_), NumElements(NumElements_) {} - - bool empty() const { return NumElements == 0; } - size_t size() const { return NumElements; } - - Node **begin() const { return Elements; } - Node **end() const { return Elements + NumElements; } - - Node *operator[](size_t Idx) const { return Elements[Idx]; } - - void printWithComma(OutputStream &S) const { - bool FirstElement = true; - for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); - if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); - - // Elements[Idx] is an empty parameter pack expansion, we should erase the - // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); - continue; - } - - FirstElement = false; - } - } -}; - -struct NodeArrayNode : Node { - NodeArray Array; - NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} - - template<typename Fn> void match(Fn F) const { F(Array); } - - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } -}; - -class DotSuffix final : public Node { - const Node *Prefix; - const StringView Suffix; - -public: - DotSuffix(const Node *Prefix_, StringView Suffix_) - : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} - - template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); } - - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; - } -}; - -class VendorExtQualType final : public Node { - const Node *Ty; - StringView Ext; - -public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Ext); } - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; - } -}; - -enum FunctionRefQual : unsigned char { - FrefQualNone, - FrefQualLValue, - FrefQualRValue, -}; - -enum Qualifiers { - QualNone = 0, - QualConst = 0x1, - QualVolatile = 0x2, - QualRestrict = 0x4, -}; - -inline Qualifiers operator|=(Qualifiers &Q1, Qualifiers Q2) { - return Q1 = static_cast<Qualifiers>(Q1 | Q2); -} - -class QualType : public Node { -protected: - const Qualifiers Quals; - const Node *Child; - - void printQuals(OutputStream &S) const { - if (Quals & QualConst) - S += " const"; - if (Quals & QualVolatile) - S += " volatile"; - if (Quals & QualRestrict) - S += " restrict"; - } - -public: - QualType(const Node *Child_, Qualifiers Quals_) - : Node(KQualType, Child_->RHSComponentCache, - Child_->ArrayCache, Child_->FunctionCache), - Quals(Quals_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child, Quals); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); - } - - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); - } - - void printRight(OutputStream &S) const override { Child->printRight(S); } -}; - -class ConversionOperatorType final : public Node { - const Node *Ty; - -public: - ConversionOperatorType(const Node *Ty_) - : Node(KConversionOperatorType), Ty(Ty_) {} - - template<typename Fn> void match(Fn F) const { F(Ty); } - - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); - } -}; - -class PostfixQualifiedType final : public Node { - const Node *Ty; - const StringView Postfix; - -public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) - : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Postfix); } - - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; - } -}; - -class NameType final : public Node { - const StringView Name; - -public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Name); } - - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } - - void printLeft(OutputStream &s) const override { s += Name; } -}; - -class ElaboratedTypeSpefType : public Node { - StringView Kind; - Node *Child; -public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) - : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Kind, Child); } - - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); - } -}; - -struct AbiTagAttr : Node { - Node *Base; - StringView Tag; - - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), - Base(Base_), Tag(Tag_) {} - - template<typename Fn> void match(Fn F) const { F(Base, Tag); } - - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; - } -}; - -class EnableIfAttr : public Node { - NodeArray Conditions; -public: - EnableIfAttr(NodeArray Conditions_) - : Node(KEnableIfAttr), Conditions(Conditions_) {} - - template<typename Fn> void match(Fn F) const { F(Conditions); } - - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; - } -}; - -class ObjCProtoName : public Node { - const Node *Ty; - StringView Protocol; - - friend class PointerType; - -public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) - : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } - - bool isObjCObject() const { - return Ty->getKind() == KNameType && - static_cast<const NameType *>(Ty)->getName() == "objc_object"; - } - - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; - } -}; - -class PointerType final : public Node { - const Node *Pointee; - -public: - PointerType(const Node *Pointee_) - : Node(KPointerType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} - - template<typename Fn> void match(Fn F) const { F(Pointee); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; - } else { - const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; - } - } - - void printRight(OutputStream &s) const override { - if (Pointee->getKind() != KObjCProtoName || - !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); - } - } -}; - -enum class ReferenceKind { - LValue, - RValue, -}; - -// Represents either a LValue or an RValue reference type. -class ReferenceType : public Node { - const Node *Pointee; - ReferenceKind RK; - - mutable bool Printing = false; - - // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The - // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any - // other combination collapses to a lvalue ref. - std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const { - auto SoFar = std::make_pair(RK, Pointee); - for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); - if (SN->getKind() != KReferenceType) - break; - auto *RT = static_cast<const ReferenceType *>(SN); - SoFar.second = RT->Pointee; - SoFar.first = std::min(SoFar.first, RT->RK); - } - return SoFar; - } - -public: - ReferenceType(const Node *Pointee_, ReferenceKind RK_) - : Node(KReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_), RK(RK_) {} - - template<typename Fn> void match(Fn F) const { F(Pointee, RK); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; - - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); - } - void printRight(OutputStream &s) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); - } -}; - -class PointerToMemberType final : public Node { - const Node *ClassType; - const Node *MemberType; - -public: - PointerToMemberType(const Node *ClassType_, const Node *MemberType_) - : Node(KPointerToMemberType, MemberType_->RHSComponentCache), - ClassType(ClassType_), MemberType(MemberType_) {} - - template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; - else - s += " "; - ClassType->print(s); - s += "::*"; - } - - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); - } -}; - -class NodeOrString { - const void *First; - const void *Second; - -public: - /* implicit */ NodeOrString(StringView Str) { - const char *FirstChar = Str.begin(); - const char *SecondChar = Str.end(); - if (SecondChar == nullptr) { - assert(FirstChar == SecondChar); - ++FirstChar, ++SecondChar; - } - First = static_cast<const void *>(FirstChar); - Second = static_cast<const void *>(SecondChar); - } - - /* implicit */ NodeOrString(Node *N) - : First(static_cast<const void *>(N)), Second(nullptr) {} - NodeOrString() : First(nullptr), Second(nullptr) {} - - bool isString() const { return Second && First; } - bool isNode() const { return First && !Second; } - bool isEmpty() const { return !First && !Second; } - - StringView asString() const { - assert(isString()); - return StringView(static_cast<const char *>(First), - static_cast<const char *>(Second)); - } - - const Node *asNode() const { - assert(isNode()); - return static_cast<const Node *>(First); - } -}; - -class ArrayType final : public Node { - const Node *Base; - NodeOrString Dimension; - -public: - ArrayType(const Node *Base_, NodeOrString Dimension_) - : Node(KArrayType, - /*RHSComponentCache=*/Cache::Yes, - /*ArrayCache=*/Cache::Yes), - Base(Base_), Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(Base, Dimension); } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } - - void printLeft(OutputStream &S) const override { Base->printLeft(S); } - - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; - if (Dimension.isString()) - S += Dimension.asString(); - else if (Dimension.isNode()) - Dimension.asNode()->print(S); - S += "]"; - Base->printRight(S); - } -}; - -class FunctionType final : public Node { - const Node *Ret; - NodeArray Params; - Qualifiers CVQuals; - FunctionRefQual RefQual; - const Node *ExceptionSpec; - -public: - FunctionType(const Node *Ret_, NodeArray Params_, Qualifiers CVQuals_, - FunctionRefQual RefQual_, const Node *ExceptionSpec_) - : Node(KFunctionType, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_), - ExceptionSpec(ExceptionSpec_) {} - - template<typename Fn> void match(Fn F) const { - F(Ret, Params, CVQuals, RefQual, ExceptionSpec); - } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } - - // Handle C++'s ... quirky decl grammar by using the left & right - // distinction. Consider: - // int (*f(float))(char) {} - // f is a function that takes a float and returns a pointer to a function - // that takes a char and returns an int. If we're trying to print f, start - // by printing out the return types's left, then print our parameters, then - // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; - } - - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); - } - } -}; - -class NoexceptSpec : public Node { - const Node *E; -public: - NoexceptSpec(const Node *E_) : Node(KNoexceptSpec), E(E_) {} - - template<typename Fn> void match(Fn F) const { F(E); } - - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; - } -}; - -class DynamicExceptionSpec : public Node { - NodeArray Types; -public: - DynamicExceptionSpec(NodeArray Types_) - : Node(KDynamicExceptionSpec), Types(Types_) {} - - template<typename Fn> void match(Fn F) const { F(Types); } - - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; - } -}; - -class FunctionEncoding final : public Node { - const Node *Ret; - const Node *Name; - NodeArray Params; - const Node *Attrs; - Qualifiers CVQuals; - FunctionRefQual RefQual; - -public: - FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, - const Node *Attrs_, Qualifiers CVQuals_, - FunctionRefQual RefQual_) - : Node(KFunctionEncoding, - /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, - /*FunctionCache=*/Cache::Yes), - Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), - CVQuals(CVQuals_), RefQual(RefQual_) {} - - template<typename Fn> void match(Fn F) const { - F(Ret, Name, Params, Attrs, CVQuals, RefQual); - } - - Qualifiers getCVQuals() const { return CVQuals; } - FunctionRefQual getRefQual() const { return RefQual; } - NodeArray getParams() const { return Params; } - const Node *getReturnType() const { return Ret; } - - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } - - const Node *getName() const { return Name; } - - void printLeft(OutputStream &S) const override { - if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; - } - Name->print(S); - } - - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - if (Ret) - Ret->printRight(S); - - if (CVQuals & QualConst) - S += " const"; - if (CVQuals & QualVolatile) - S += " volatile"; - if (CVQuals & QualRestrict) - S += " restrict"; - - if (RefQual == FrefQualLValue) - S += " &"; - else if (RefQual == FrefQualRValue) - S += " &&"; - - if (Attrs != nullptr) - Attrs->print(S); - } -}; - -class LiteralOperator : public Node { - const Node *OpName; - -public: - LiteralOperator(const Node *OpName_) - : Node(KLiteralOperator), OpName(OpName_) {} - - template<typename Fn> void match(Fn F) const { F(OpName); } - - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); - } -}; - -class SpecialName final : public Node { - const StringView Special; - const Node *Child; - -public: - SpecialName(StringView Special_, const Node *Child_) - : Node(KSpecialName), Special(Special_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Special, Child); } - - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); - } -}; - -class CtorVtableSpecialName final : public Node { - const Node *FirstType; - const Node *SecondType; - -public: - CtorVtableSpecialName(const Node *FirstType_, const Node *SecondType_) - : Node(KCtorVtableSpecialName), - FirstType(FirstType_), SecondType(SecondType_) {} - - template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } - - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); - } -}; - -struct NestedName : Node { - Node *Qual; - Node *Name; - - NestedName(Node *Qual_, Node *Name_) - : Node(KNestedName), Qual(Qual_), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Qual, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); - } -}; - -struct LocalName : Node { - Node *Encoding; - Node *Entity; - - LocalName(Node *Encoding_, Node *Entity_) - : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} - - template<typename Fn> void match(Fn F) const { F(Encoding, Entity); } - - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); - } -}; - -class QualifiedName final : public Node { - // qualifier::name - const Node *Qualifier; - const Node *Name; - -public: - QualifiedName(const Node *Qualifier_, const Node *Name_) - : Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {} - - template<typename Fn> void match(Fn F) const { F(Qualifier, Name); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); - } -}; - -class VectorType final : public Node { - const Node *BaseType; - const NodeOrString Dimension; - -public: - VectorType(const Node *BaseType_, NodeOrString Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } - - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; - if (Dimension.isNode()) - Dimension.asNode()->print(S); - else if (Dimension.isString()) - S += Dimension.asString(); - S += "]"; - } -}; - -class PixelVectorType final : public Node { - const NodeOrString Dimension; - -public: - PixelVectorType(NodeOrString Dimension_) - : Node(KPixelVectorType), Dimension(Dimension_) {} - - template<typename Fn> void match(Fn F) const { F(Dimension); } - - void printLeft(OutputStream &S) const override { - // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - S += Dimension.asString(); - S += "]"; - } -}; - -/// An unexpanded parameter pack (either in the expression or type context). If -/// this AST is correct, this node will have a ParameterPackExpansion node above -/// it. -/// -/// This node is created when some <template-args> are found that apply to an -/// <encoding>, and is stored in the TemplateParams table. In order for this to -/// appear in the final AST, it has to referenced via a <template-param> (ie, -/// T_). -class ParameterPack final : public Node { - NodeArray Data; - - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) { - S.CurrentPackMax = static_cast<unsigned>(Data.size()); - S.CurrentPackIndex = 0; - } - } - -public: - ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) { - ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->ArrayCache == Cache::No; - })) - ArrayCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->FunctionCache == Cache::No; - })) - FunctionCache = Cache::No; - if (std::all_of(Data.begin(), Data.end(), [](Node* P) { - return P->RHSComponentCache == Cache::No; - })) - RHSComponentCache = Cache::No; - } - - template<typename Fn> void match(Fn F) const { F(Data); } - - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; - } - - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printLeft(S); - } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - if (Idx < Data.size()) - Data[Idx]->printRight(S); - } -}; - -/// A variadic template argument. This node represents an occurrence of -/// J<something>E in some <template-args>. It isn't itself unexpanded, unless -/// one of it's Elements is. The parser inserts a ParameterPack into the -/// TemplateParams table if the <template-args> this pack belongs to apply to an -/// <encoding>. -class TemplateArgumentPack final : public Node { - NodeArray Elements; -public: - TemplateArgumentPack(NodeArray Elements_) - : Node(KTemplateArgumentPack), Elements(Elements_) {} - - template<typename Fn> void match(Fn F) const { F(Elements); } - - NodeArray getElements() const { return Elements; } - - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); - } -}; - -/// A pack expansion. Below this node, there are some unexpanded ParameterPacks -/// which each have Child->ParameterPackSize elements. -class ParameterPackExpansion final : public Node { - const Node *Child; - -public: - ParameterPackExpansion(const Node *Child_) - : Node(KParameterPackExpansion), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - const Node *getChild() const { return Child; } - - void printLeft(OutputStream &S) const override { - constexpr unsigned Max = std::numeric_limits<unsigned>::max(); - SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); - - // Print the first element in the pack. If Child contains a ParameterPack, - // it will set up S.CurrentPackMax and print the first element. - Child->print(S); - - // No ParameterPack was found in Child. This can occur if we've found a pack - // expansion on a <function-param>. - if (S.CurrentPackMax == Max) { - S += "..."; - return; - } - - // We found a ParameterPack, but it has no elements. Erase whatever we may - // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); - return; - } - - // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); - } - } -}; - -class TemplateArgs final : public Node { - NodeArray Params; - -public: - TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} - - template<typename Fn> void match(Fn F) const { F(Params); } - - NodeArray getParams() { return Params; } - - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; - } -}; - -/// A forward-reference to a template argument that was not known at the point -/// where the template parameter name was parsed in a mangling. -/// -/// This is created when demangling the name of a specialization of a -/// conversion function template: -/// -/// \code -/// struct A { -/// template<typename T> operator T*(); -/// }; -/// \endcode -/// -/// When demangling a specialization of the conversion function template, we -/// encounter the name of the template (including the \c T) before we reach -/// the template argument list, so we cannot substitute the parameter name -/// for the corresponding argument while parsing. Instead, we create a -/// \c ForwardTemplateReference node that is resolved after we parse the -/// template arguments. -struct ForwardTemplateReference : Node { - size_t Index; - Node *Ref = nullptr; - - // If we're currently printing this node. It is possible (though invalid) for - // a forward template reference to refer to itself via a substitution. This - // creates a cyclic AST, which will stack overflow printing. To fix this, bail - // out if more than one print* function is active. - mutable bool Printing = false; - - ForwardTemplateReference(size_t Index_) - : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, - Cache::Unknown), - Index(Index_) {} - - // We don't provide a matcher for these, because the value of the node is - // not determined by its construction parameters, and it generally needs - // special handling. - template<typename Fn> void match(Fn F) const = delete; - - bool hasRHSComponentSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); - } - bool hasArraySlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasArray(S); - } - bool hasFunctionSlow(OutputStream &S) const override { - if (Printing) - return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasFunction(S); - } - const Node *getSyntaxNode(OutputStream &S) const override { - if (Printing) - return this; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); - } - - void printLeft(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printLeft(S); - } - void printRight(OutputStream &S) const override { - if (Printing) - return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printRight(S); - } -}; - -struct NameWithTemplateArgs : Node { - // name<template_args> - Node *Name; - Node *TemplateArgs; - - NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) - : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} - - template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); } - - StringView getBaseName() const override { return Name->getBaseName(); } - - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); - } -}; - -class GlobalQualifiedName final : public Node { - Node *Child; - -public: - GlobalQualifiedName(Node* Child_) - : Node(KGlobalQualifiedName), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); - } -}; - -enum class SpecialSubKind { - allocator, - basic_string, - string, - istream, - ostream, - iostream, -}; - -class ExpandedSpecialSubstitution final : public Node { - SpecialSubKind SSK; - -public: - ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} - - template<typename Fn> void match(Fn F) const { F(SSK); } - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("basic_string"); - case SpecialSubKind::istream: - return StringView("basic_istream"); - case SpecialSubKind::ostream: - return StringView("basic_ostream"); - case SpecialSubKind::iostream: - return StringView("basic_iostream"); - } - _LIBCPP_UNREACHABLE(); - } - - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream<char, std::char_traits<char> >"; - break; - } - } -}; - -class SpecialSubstitution final : public Node { -public: - SpecialSubKind SSK; - - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} - - template<typename Fn> void match(Fn F) const { F(SSK); } - - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); - } - _LIBCPP_UNREACHABLE(); - } - - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::string"; - break; - case SpecialSubKind::istream: - S += "std::istream"; - break; - case SpecialSubKind::ostream: - S += "std::ostream"; - break; - case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } - } -}; - -class CtorDtorName final : public Node { - const Node *Basename; - const bool IsDtor; - const int Variant; - -public: - CtorDtorName(const Node *Basename_, bool IsDtor_, int Variant_) - : Node(KCtorDtorName), Basename(Basename_), IsDtor(IsDtor_), - Variant(Variant_) {} - - template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } - - void printLeft(OutputStream &S) const override { - if (IsDtor) - S += "~"; - S += Basename->getBaseName(); - } -}; - -class DtorName : public Node { - const Node *Base; - -public: - DtorName(const Node *Base_) : Node(KDtorName), Base(Base_) {} - - template<typename Fn> void match(Fn F) const { F(Base); } - - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); - } -}; - -class UnnamedTypeName : public Node { - const StringView Count; - -public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} - - template<typename Fn> void match(Fn F) const { F(Count); } - - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; - } -}; - -class ClosureTypeName : public Node { - NodeArray Params; - StringView Count; - -public: - ClosureTypeName(NodeArray Params_, StringView Count_) - : Node(KClosureTypeName), Params(Params_), Count(Count_) {} - - template<typename Fn> void match(Fn F) const { F(Params, Count); } - - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'("; - Params.printWithComma(S); - S += ")"; - } -}; - -class StructuredBindingName : public Node { - NodeArray Bindings; -public: - StructuredBindingName(NodeArray Bindings_) - : Node(KStructuredBindingName), Bindings(Bindings_) {} - - template<typename Fn> void match(Fn F) const { F(Bindings); } - - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; - } -}; - -// -- Expression Nodes -- - -class BinaryExpr : public Node { - const Node *LHS; - const StringView InfixOperator; - const Node *RHS; - -public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { - } - - template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); } - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; - } -}; - -class ArraySubscriptExpr : public Node { - const Node *Op1; - const Node *Op2; - -public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} - - template<typename Fn> void match(Fn F) const { F(Op1, Op2); } - - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; - } -}; - -class PostfixExpr : public Node { - const Node *Child; - const StringView Operator; - -public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} - - template<typename Fn> void match(Fn F) const { F(Child, Operator); } - - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; - } -}; - -class ConditionalExpr : public Node { - const Node *Cond; - const Node *Then; - const Node *Else; - -public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} - - template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); } - - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; - } -}; - -class MemberExpr : public Node { - const Node *LHS; - const StringView Kind; - const Node *RHS; - -public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} - - template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); } - - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); - } -}; - -class EnclosingExpr : public Node { - const StringView Prefix; - const Node *Infix; - const StringView Postfix; - -public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} - - template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); } - - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; - } -}; - -class CastExpr : public Node { - // cast_kind<to>(from) - const StringView CastKind; - const Node *To; - const Node *From; - -public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_) - : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} - - template<typename Fn> void match(Fn F) const { F(CastKind, To, From); } - - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; - } -}; - -class SizeofParamPackExpr : public Node { - const Node *Pack; - -public: - SizeofParamPackExpr(const Node *Pack_) - : Node(KSizeofParamPackExpr), Pack(Pack_) {} - - template<typename Fn> void match(Fn F) const { F(Pack); } - - void printLeft(OutputStream &S) const override { - S += "sizeof...("; - ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; - } -}; - -class CallExpr : public Node { - const Node *Callee; - NodeArray Args; - -public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} - - template<typename Fn> void match(Fn F) const { F(Callee, Args); } - - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; - } -}; - -class NewExpr : public Node { - // new (expr_list) type(init_list) - NodeArray ExprList; - Node *Type; - NodeArray InitList; - bool IsGlobal; // ::operator new ? - bool IsArray; // new[] ? -public: - NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - template<typename Fn> void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); - } - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::operator "; - S += "new"; - if (IsArray) - S += "[]"; - S += ' '; - if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; - } - Type->print(S); - if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; - } - - } -}; - -class DeleteExpr : public Node { - Node *Op; - bool IsGlobal; - bool IsArray; - -public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} - - template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); } - - void printLeft(OutputStream &S) const override { - if (IsGlobal) - S += "::"; - S += "delete"; - if (IsArray) - S += "[] "; - Op->print(S); - } -}; - -class PrefixExpr : public Node { - StringView Prefix; - Node *Child; - -public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Prefix, Child); } - - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; - } -}; - -class FunctionParam : public Node { - StringView Number; - -public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} - - template<typename Fn> void match(Fn F) const { F(Number); } - - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; - } -}; - -class ConversionExpr : public Node { - const Node *Type; - NodeArray Expressions; - -public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} - - template<typename Fn> void match(Fn F) const { F(Type, Expressions); } - - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; - } -}; - -class InitListExpr : public Node { - const Node *Ty; - NodeArray Inits; -public: - InitListExpr(const Node *Ty_, NodeArray Inits_) - : Node(KInitListExpr), Ty(Ty_), Inits(Inits_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Inits); } - - void printLeft(OutputStream &S) const override { - if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; - } -}; - -class BracedExpr : public Node { - const Node *Elem; - const Node *Init; - bool IsArray; -public: - BracedExpr(const Node *Elem_, const Node *Init_, bool IsArray_) - : Node(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {} - - template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } - - void printLeft(OutputStream &S) const override { - if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; - } else { - S += '.'; - Elem->print(S); - } - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); - } -}; - -class BracedRangeExpr : public Node { - const Node *First; - const Node *Last; - const Node *Init; -public: - BracedRangeExpr(const Node *First_, const Node *Last_, const Node *Init_) - : Node(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {} - - template<typename Fn> void match(Fn F) const { F(First, Last, Init); } - - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; - if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); - } -}; - -class FoldExpr : public Node { - const Node *Pack, *Init; - StringView OperatorName; - bool IsLeftFold; - -public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, - const Node *Init_) - : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), - IsLeftFold(IsLeftFold_) {} - - template<typename Fn> void match(Fn F) const { - F(IsLeftFold, OperatorName, Pack, Init); - } - - void printLeft(OutputStream &S) const override { - auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; - }; - - S += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } - } - S += ')'; - } -}; - -class ThrowExpr : public Node { - const Node *Op; - -public: - ThrowExpr(const Node *Op_) : Node(KThrowExpr), Op(Op_) {} - - template<typename Fn> void match(Fn F) const { F(Op); } - - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -class BoolExpr : public Node { - bool Value; - -public: - BoolExpr(bool Value_) : Node(KBoolExpr), Value(Value_) {} - - template<typename Fn> void match(Fn F) const { F(Value); } - - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); - } -}; - -class IntegerCastExpr : public Node { - // ty(integer) - const Node *Ty; - StringView Integer; - -public: - IntegerCastExpr(const Node *Ty_, StringView Integer_) - : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} - - template<typename Fn> void match(Fn F) const { F(Ty, Integer); } - - void printLeft(OutputStream &S) const override { - S += "("; - Ty->print(S); - S += ")"; - S += Integer; - } -}; - -class IntegerLiteral : public Node { - StringView Type; - StringView Value; - -public: - IntegerLiteral(StringView Type_, StringView Value_) - : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} - - template<typename Fn> void match(Fn F) const { F(Type, Value); } - - void printLeft(OutputStream &S) const override { - if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; - } - - if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); - } else - S += Value; - - if (Type.size() <= 3) - S += Type; - } -}; - -template <class Float> struct FloatData; - -namespace float_literal_impl { -constexpr Node::Kind getFloatLiteralKind(float *) { - return Node::KFloatLiteral; -} -constexpr Node::Kind getFloatLiteralKind(double *) { - return Node::KDoubleLiteral; -} -constexpr Node::Kind getFloatLiteralKind(long double *) { - return Node::KLongDoubleLiteral; -} -} - -template <class Float> class FloatLiteralImpl : public Node { - const StringView Contents; - - static constexpr Kind KindForClass = - float_literal_impl::getFloatLiteralKind((Float *)nullptr); - -public: - FloatLiteralImpl(StringView Contents_) - : Node(KindForClass), Contents(Contents_) {} - - template<typename Fn> void match(Fn F) const { F(Contents); } - - void printLeft(OutputStream &s) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - - const size_t N = FloatData<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) { - last = first + N; - union { - Float value; - char buf[sizeof(Float)]; - }; - const char *t = first; - char *e = buf; - for (; t != last; ++t, ++e) { - unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - ++t; - unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') - : static_cast<unsigned>(*t - 'a' + 10); - *e = static_cast<char>((d1 << 4) + d0); - } -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - std::reverse(buf, e); -#endif - char num[FloatData<Float>::max_demangled_size] = {0}; - int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); - s += StringView(num, num + n); - } - } -}; - -using FloatLiteral = FloatLiteralImpl<float>; -using DoubleLiteral = FloatLiteralImpl<double>; -using LongDoubleLiteral = FloatLiteralImpl<long double>; - -/// Visit the node. Calls \c F(P), where \c P is the node cast to the -/// appropriate derived class. -template<typename Fn> -void Node::visit(Fn F) const { - switch (K) { -#define CASE(X) case K ## X: return F(static_cast<const X*>(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE - } - assert(0 && "unknown mangling node kind"); -} - -/// Determine the kind of a node from its type. -template<typename NodeT> struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind<X> { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ - }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef SPECIALIZATION - -#undef FOR_EACH_NODE_KIND - -template <class T, size_t N> -class PODSmallVector { - static_assert(std::is_pod<T>::value, - "T is required to be a plain old data type"); - - T* First; - T* Last; - T* Cap; - T Inline[N]; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; - -template <typename Derived, typename Alloc> struct AbstractManglingParser { - const char *First; - const char *Last; - - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser collapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector<Node *, 32> Names; - - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector<Node *, 32> Subs; - - // Template parameter table. Like the above, but referenced like "T42_". - // This has a smaller size compared to Subs and Names because it can be - // stored on the stack. - PODSmallVector<Node *, 8> TemplateParams; - - // Set of unresolved forward <template-param> references. These can occur in a - // conversion operator's type, and are resolved in the enclosing <encoding>. - PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; - - bool TryToParseTemplateArgs = true; - bool PermitForwardTemplateReferences = false; - bool ParsingLambdaParams = false; - - Alloc ASTAllocator; - - AbstractManglingParser(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - - Derived &getDerived() { return static_cast<Derived &>(*this); } - - void reset(const char *First_, const char *Last_) { - First = First_; - Last = Last_; - Names.clear(); - Subs.clear(); - TemplateParams.clear(); - ParsingLambdaParams = false; - TryToParseTemplateArgs = true; - PermitForwardTemplateReferences = false; - ASTAllocator.reset(); - } - - template <class T, class... Args> Node *make(Args &&... args) { - return ASTAllocator.template makeNode<T>(std::forward<Args>(args)...); - } - - template <class It> NodeArray makeNodeArray(It begin, It end) { - size_t sz = static_cast<size_t>(end - begin); - void *mem = ASTAllocator.allocateNodeArray(sz); - Node **data = new (mem) Node *[sz]; - std::copy(begin, end, data); - return NodeArray(data, sz); - } - - NodeArray popTrailingNodeArray(size_t FromPosition) { - assert(FromPosition <= Names.size()); - NodeArray res = - makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); - return res; - } - - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { - First += S.size(); - return true; - } - return false; - } - - bool consumeIf(char C) { - if (First != Last && *First == C) { - ++First; - return true; - } - return false; - } - - char consume() { return First != Last ? *First++ : '\0'; } - - char look(unsigned Lookahead = 0) { - if (static_cast<size_t>(Last - First) <= Lookahead) - return '\0'; - return First[Lookahead]; - } - - size_t numLeft() const { return static_cast<size_t>(Last - First); } - - StringView parseNumber(bool AllowNegative = false); - Qualifiers parseCVQualifiers(); - bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); - - bool parseSeqId(size_t *Out); - Node *parseSubstitution(); - Node *parseTemplateParam(); - Node *parseTemplateArgs(bool TagTemplates = false); - Node *parseTemplateArg(); - - /// Parse the <expr> production. - Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); - Node *parseIntegerLiteral(StringView Lit); - Node *parseExprPrimary(); - template <class Float> Node *parseFloatingLiteral(); - Node *parseFunctionParam(); - Node *parseNewExpr(); - Node *parseConversionExpr(); - Node *parseBracedExpr(); - Node *parseFoldExpr(); - - /// Parse the <type> production. - Node *parseType(); - Node *parseFunctionType(); - Node *parseVectorType(); - Node *parseDecltype(); - Node *parseArrayType(); - Node *parsePointerToMemberType(); - Node *parseClassEnumType(); - Node *parseQualifiedType(); - - Node *parseEncoding(); - bool parseCallOffset(); - Node *parseSpecialName(); - - /// Holds some extra information about a <name> that is being parsed. This - /// information is only pertinent if the <name> refers to an <encoding>. - struct NameState { - bool CtorDtorConversion = false; - bool EndsWithTemplateArgs = false; - Qualifiers CVQualifiers = QualNone; - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ForwardTemplateRefsBegin; - - NameState(AbstractManglingParser *Enclosing) - : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} - }; - - bool resolveForwardTemplateRefs(NameState &State) { - size_t I = State.ForwardTemplateRefsBegin; - size_t E = ForwardTemplateRefs.size(); - for (; I < E; ++I) { - size_t Idx = ForwardTemplateRefs[I]->Index; - if (Idx >= TemplateParams.size()) - return true; - ForwardTemplateRefs[I]->Ref = TemplateParams[Idx]; - } - ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); - return false; - } - - /// Parse the <name> production> - Node *parseName(NameState *State = nullptr); - Node *parseLocalName(NameState *State); - Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); - Node *parseUnnamedTypeName(NameState *State); - Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); - Node *parseNestedName(NameState *State); - Node *parseCtorDtorName(Node *&SoFar, NameState *State); - - Node *parseAbiTags(Node *N); - - /// Parse the <unresolved-name> production. - Node *parseUnresolvedName(); - Node *parseSimpleId(); - Node *parseBaseUnresolvedName(); - Node *parseUnresolvedType(); - Node *parseDestructorName(); - - /// Top-level entry point into the parser. - Node *parse(); -}; - -const char* parse_discriminator(const char* first, const char* last); - -// <name> ::= <nested-name> // N -// ::= <local-name> # See Scope Encoding below // Z -// ::= <unscoped-template-name> <template-args> -// ::= <unscoped-name> -// -// <unscoped-template-name> ::= <unscoped-name> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { - consumeIf('L'); // extension - - if (look() == 'N') - return getDerived().parseNestedName(State); - if (look() == 'Z') - return getDerived().parseLocalName(State); - - // ::= <unscoped-template-name> <template-args> - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(S, TA); - } - - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= <unscoped-template-name> <template-args> - if (look() == 'I') { - Subs.push_back(N); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(N, TA); - } - // ::= <unscoped-name> - return N; -} - -// <local-name> := Z <function encoding> E <entity name> [<discriminator>] -// := Z <function encoding> E s [<discriminator>] -// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) { - if (!consumeIf('Z')) - return nullptr; - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf('E')) - return nullptr; - - if (consumeIf('s')) { - First = parse_discriminator(First, Last); - auto *StringLitName = make<NameType>("string literal"); - if (!StringLitName) - return nullptr; - return make<LocalName>(Encoding, StringLitName); - } - - if (consumeIf('d')) { - parseNumber(true); - if (!consumeIf('_')) - return nullptr; - Node *N = getDerived().parseName(State); - if (N == nullptr) - return nullptr; - return make<LocalName>(Encoding, N); - } - - Node *Entity = getDerived().parseName(State); - if (Entity == nullptr) - return nullptr; - First = parse_discriminator(First, Last); - return make<LocalName>(Encoding, Entity); -} - -// <unscoped-name> ::= <unqualified-name> -// ::= St <unqualified-name> # ::std:: -// extension ::= StL<unqualified-name> -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make<StdQualifiedName>(R); - } - return getDerived().parseUnqualifiedName(State); -} - -// <unqualified-name> ::= <operator-name> [abi-tags] -// ::= <ctor-dtor-name> -// ::= <source-name> -// ::= <unnamed-type-name> -// ::= DC <source-name>+ E # structured binding declaration -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { - // <ctor-dtor-name>s are special-cased in parseNestedName(). - Node *Result; - if (look() == 'U') - Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') - Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { - size_t BindingsBegin = Names.size(); - do { - Node *Binding = getDerived().parseSourceName(State); - if (Binding == nullptr) - return nullptr; - Names.push_back(Binding); - } while (!consumeIf('E')); - Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); - } else - Result = getDerived().parseOperatorName(State); - if (Result != nullptr) - Result = getDerived().parseAbiTags(Result); - return Result; -} - -// <unnamed-type-name> ::= Ut [<nonnegative number>] _ -// ::= <closure-type-name> -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// -// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *) { - if (consumeIf("Ut")) { - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<UnnamedTypeName>(Count); - } - if (consumeIf("Ul")) { - NodeArray Params; - SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true); - if (!consumeIf("vE")) { - size_t ParamsBegin = Names.size(); - do { - Node *P = getDerived().parseType(); - if (P == nullptr) - return nullptr; - Names.push_back(P); - } while (!consumeIf('E')); - Params = popTrailingNodeArray(ParamsBegin); - } - StringView Count = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<ClosureTypeName>(Params, Count); - } - return nullptr; -} - -// <source-name> ::= <positive length number> <identifier> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) { - size_t Length = 0; - if (parsePositiveInteger(&Length)) - return nullptr; - if (numLeft() < Length || Length == 0) - return nullptr; - StringView Name(First, First + Length); - First += Length; - if (Name.startsWith("_GLOBAL__N")) - return make<NameType>("(anonymous namespace)"); - return make<NameType>(Name); -} - -// <operator-name> ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv <type> # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= li <source-name> # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in <expression> context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in <expression> context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v <digit> <source-name> # vendor extended operator -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator&&"); - case 'd': - case 'n': - First += 2; - return make<NameType>("operator&"); - case 'N': - First += 2; - return make<NameType>("operator&="); - case 'S': - First += 2; - return make<NameType>("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make<NameType>("operator()"); - case 'm': - First += 2; - return make<NameType>("operator,"); - case 'o': - First += 2; - return make<NameType>("operator~"); - // ::= cv <type> # (cast) - case 'v': { - First += 2; - SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); - // If we're parsing an encoding, State != nullptr and the conversion - // operators' <type> could have a <template-param> that refers to some - // <template-arg>s further ahead in the mangled name. - SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, - PermitForwardTemplateReferences || - State != nullptr); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (State) State->CtorDtorConversion = true; - return make<ConversionOperatorType>(Ty); - } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator delete[]"); - case 'e': - First += 2; - return make<NameType>("operator*"); - case 'l': - First += 2; - return make<NameType>("operator delete"); - case 'v': - First += 2; - return make<NameType>("operator/"); - case 'V': - First += 2; - return make<NameType>("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator^"); - case 'O': - First += 2; - return make<NameType>("operator^="); - case 'q': - First += 2; - return make<NameType>("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator>="); - case 't': - First += 2; - return make<NameType>("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make<NameType>("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator<="); - // ::= li <source-name> # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<LiteralOperator>(SN); - } - case 's': - First += 2; - return make<NameType>("operator<<"); - case 'S': - First += 2; - return make<NameType>("operator<<="); - case 't': - First += 2; - return make<NameType>("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make<NameType>("operator-"); - case 'I': - First += 2; - return make<NameType>("operator-="); - case 'l': - First += 2; - return make<NameType>("operator*"); - case 'L': - First += 2; - return make<NameType>("operator*="); - case 'm': - First += 2; - return make<NameType>("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator new[]"); - case 'e': - First += 2; - return make<NameType>("operator!="); - case 'g': - First += 2; - return make<NameType>("operator-"); - case 't': - First += 2; - return make<NameType>("operator!"); - case 'w': - First += 2; - return make<NameType>("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator||"); - case 'r': - First += 2; - return make<NameType>("operator|"); - case 'R': - First += 2; - return make<NameType>("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator->*"); - case 'l': - First += 2; - return make<NameType>("operator+"); - case 'L': - First += 2; - return make<NameType>("operator+="); - case 'p': - First += 2; - return make<NameType>("operator++"); - case 's': - First += 2; - return make<NameType>("operator+"); - case 't': - First += 2; - return make<NameType>("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make<NameType>("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator%"); - case 'M': - First += 2; - return make<NameType>("operator%="); - case 's': - First += 2; - return make<NameType>("operator>>"); - case 'S': - First += 2; - return make<NameType>("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make<NameType>("operator<=>"); - } - return nullptr; - // ::= v <digit> <source-name> # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<ConversionOperatorType>(SN); - } - return nullptr; - } - return nullptr; -} - -// <ctor-dtor-name> ::= 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 <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, - NameState *State) { - if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make<ExpandedSpecialSubstitution>(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } - } - - if (consumeIf('C')) { - bool IsInherited = consumeIf('I'); - if (look() != '1' && look() != '2' && look() != '3' && look() != '5') - return nullptr; - int Variant = look() - '0'; - ++First; - if (State) State->CtorDtorConversion = true; - if (IsInherited) { - if (getDerived().parseName(State) == nullptr) - return nullptr; - } - return make<CtorDtorName>(SoFar, false, Variant); - } - - if (look() == 'D' && - (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) { - int Variant = look(1) - '0'; - First += 2; - if (State) State->CtorDtorConversion = true; - return make<CtorDtorName>(SoFar, true, Variant); - } - - return nullptr; -} - -// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E -// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E -// -// <prefix> ::= <prefix> <unqualified-name> -// ::= <template-prefix> <template-args> -// ::= <template-param> -// ::= <decltype> -// ::= # empty -// ::= <substitution> -// ::= <prefix> <data-member-prefix> -// extension ::= L -// -// <data-member-prefix> := <member source-name> [<template-args>] M -// -// <template-prefix> ::= <prefix> <template unqualified-name> -// ::= <template-param> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) { - if (!consumeIf('N')) - return nullptr; - - Qualifiers CVTmp = parseCVQualifiers(); - if (State) State->CVQualifiers = CVTmp; - - if (consumeIf('O')) { - if (State) State->ReferenceQualifier = FrefQualRValue; - } else if (consumeIf('R')) { - if (State) State->ReferenceQualifier = FrefQualLValue; - } else - if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make<NestedName>(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make<NameType>("std"); - if (!SoFar) - return nullptr; - } - - while (!consumeIf('E')) { - consumeIf('L'); // extension - - // <data-member-prefix> := <member source-name> [<template-args>] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } - - // ::= <template-param> - if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <template-prefix> <template-args> - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= <decltype> - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <substitution> - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) - return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } - - // Parse an <unqualified-name> thats actually a <ctor-dtor-name>. - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <prefix> <unqualified-name> - if (!PushComponent(getDerived().parseUnqualifiedName(State))) - return nullptr; - Subs.push_back(SoFar); - } - - if (SoFar == nullptr || Subs.empty()) - return nullptr; - - Subs.pop_back(); - return SoFar; -} - -// <simple-id> ::= <source-name> [ <template-args> ] -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSimpleId() { - Node *SN = getDerived().parseSourceName(/*NameState=*/nullptr); - if (SN == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(SN, TA); - } - return SN; -} - -// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) -// ::= <simple-id> # e.g., ~A<2*N> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseDestructorName() { - Node *Result; - if (std::isdigit(look())) - Result = getDerived().parseSimpleId(); - else - Result = getDerived().parseUnresolvedType(); - if (Result == nullptr) - return nullptr; - return make<DtorName>(Result); -} - -// <unresolved-type> ::= <template-param> -// ::= <decltype> -// ::= <substitution> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedType() { - if (look() == 'T') { - Node *TP = getDerived().parseTemplateParam(); - if (TP == nullptr) - return nullptr; - Subs.push_back(TP); - return TP; - } - if (look() == 'D') { - Node *DT = getDerived().parseDecltype(); - if (DT == nullptr) - return nullptr; - Subs.push_back(DT); - return DT; - } - return getDerived().parseSubstitution(); -} - -// <base-unresolved-name> ::= <simple-id> # unresolved name -// extension ::= <operator-name> # unresolved operator-function-id -// extension ::= <operator-name> <template-args> # unresolved operator template-id -// ::= on <operator-name> # unresolved operator-function-id -// ::= on <operator-name> <template-args> # unresolved operator template-id -// ::= dn <destructor-name> # destructor or pseudo-destructor; -// # e.g. ~X or ~X<N-1> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() { - if (std::isdigit(look())) - return getDerived().parseSimpleId(); - - if (consumeIf("dn")) - return getDerived().parseDestructorName(); - - consumeIf("on"); - - Node *Oper = getDerived().parseOperatorName(/*NameState=*/nullptr); - if (Oper == nullptr) - return nullptr; - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - return make<NameWithTemplateArgs>(Oper, TA); - } - return Oper; -} - -// <unresolved-name> -// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> -// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -// # A::x, N::y, A<T>::z; "gs" means leading "::" -// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x -// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> -// -// <unresolved-qualifier-level> ::= <simple-id> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { - Node *SoFar = nullptr; - - // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> - // srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> - if (consumeIf("srN")) { - SoFar = getDerived().parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - } - - while (!consumeIf('E')) { - Node *Qual = getDerived().parseSimpleId(); - if (Qual == nullptr) - return nullptr; - SoFar = make<QualifiedName>(SoFar, Qual); - if (!SoFar) - return nullptr; - } - - Node *Base = getDerived().parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); - } - - bool Global = consumeIf("gs"); - - // [gs] <base-unresolved-name> # x or (with "gs") ::x - if (!consumeIf("sr")) { - SoFar = getDerived().parseBaseUnresolvedName(); - if (SoFar == nullptr) - return nullptr; - if (Global) - SoFar = make<GlobalQualifiedName>(SoFar); - return SoFar; - } - - // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> - if (std::isdigit(look())) { - do { - Node *Qual = getDerived().parseSimpleId(); - if (Qual == nullptr) - return nullptr; - if (SoFar) - SoFar = make<QualifiedName>(SoFar, Qual); - else if (Global) - SoFar = make<GlobalQualifiedName>(Qual); - else - SoFar = Qual; - if (!SoFar) - return nullptr; - } while (!consumeIf('E')); - } - // sr <unresolved-type> <base-unresolved-name> - // sr <unresolved-type> <template-args> <base-unresolved-name> - else { - SoFar = getDerived().parseUnresolvedType(); - if (SoFar == nullptr) - return nullptr; - - if (look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - } - } - - assert(SoFar != nullptr); - - Node *Base = getDerived().parseBaseUnresolvedName(); - if (Base == nullptr) - return nullptr; - return make<QualifiedName>(SoFar, Base); -} - -// <abi-tags> ::= <abi-tag> [<abi-tags>] -// <abi-tag> ::= B <source-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { - while (consumeIf('B')) { - StringView SN = parseBareSourceName(); - if (SN.empty()) - return nullptr; - N = make<AbiTagAttr>(N, SN); - if (!N) - return nullptr; - } - return N; -} - -// <number> ::= [n] <non-negative decimal integer> -template <typename Alloc, typename Derived> -StringView -AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { - const char *Tmp = First; - if (AllowNegative) - consumeIf('n'); - if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); - while (numLeft() != 0 && std::isdigit(*First)) - ++First; - return StringView(Tmp, First); -} - -// <positive length number> ::= [0-9]* -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) { - *Out = 0; - if (look() < '0' || look() > '9') - return true; - while (look() >= '0' && look() <= '9') { - *Out *= 10; - *Out += static_cast<size_t>(consume() - '0'); - } - return false; -} - -template <typename Alloc, typename Derived> -StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { - size_t Int = 0; - if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); - First += Int; - return R; -} - -// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E -// -// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw()) -// ::= DO <expression> E # computed (instantiation-dependent) noexcept -// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types -// -// <ref-qualifier> ::= R # & ref-qualifier -// <ref-qualifier> ::= O # && ref-qualifier -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFunctionType() { - Qualifiers CVQuals = parseCVQualifiers(); - - Node *ExceptionSpec = nullptr; - if (consumeIf("Do")) { - ExceptionSpec = make<NameType>("noexcept"); - if (!ExceptionSpec) - return nullptr; - } else if (consumeIf("DO")) { - Node *E = getDerived().parseExpr(); - if (E == nullptr || !consumeIf('E')) - return nullptr; - ExceptionSpec = make<NoexceptSpec>(E); - if (!ExceptionSpec) - return nullptr; - } else if (consumeIf("Dw")) { - size_t SpecsBegin = Names.size(); - while (!consumeIf('E')) { - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - ExceptionSpec = - make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin)); - if (!ExceptionSpec) - return nullptr; - } - - consumeIf("Dx"); // transaction safe - - if (!consumeIf('F')) - return nullptr; - consumeIf('Y'); // extern "C" - Node *ReturnType = getDerived().parseType(); - if (ReturnType == nullptr) - return nullptr; - - FunctionRefQual ReferenceQualifier = FrefQualNone; - size_t ParamsBegin = Names.size(); - while (true) { - if (consumeIf('E')) - break; - if (consumeIf('v')) - continue; - if (consumeIf("RE")) { - ReferenceQualifier = FrefQualLValue; - break; - } - if (consumeIf("OE")) { - ReferenceQualifier = FrefQualRValue; - break; - } - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - Names.push_back(T); - } - - NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make<FunctionType>(ReturnType, Params, CVQuals, - ReferenceQualifier, ExceptionSpec); -} - -// extension: -// <vector-type> ::= Dv <positive dimension number> _ <extended element type> -// ::= Dv [<dimension expression>] _ <element type> -// <extended element type> ::= <element type> -// ::= p # AltiVec vector pixel -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() { - if (!consumeIf("Dv")) - return nullptr; - if (look() >= '1' && look() <= '9') { - StringView DimensionNumber = parseNumber(); - if (!consumeIf('_')) - return nullptr; - if (consumeIf('p')) - return make<PixelVectorType>(DimensionNumber); - Node *ElemType = getDerived().parseType(); - if (ElemType == nullptr) - return nullptr; - return make<VectorType>(ElemType, DimensionNumber); - } - - if (!consumeIf('_')) { - Node *DimExpr = getDerived().parseExpr(); - if (!DimExpr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Node *ElemType = getDerived().parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, DimExpr); - } - Node *ElemType = getDerived().parseType(); - if (!ElemType) - return nullptr; - return make<VectorType>(ElemType, StringView()); -} - -// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) -// ::= DT <expression> E # decltype of an expression (C++0x) -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() { - if (!consumeIf('D')) - return nullptr; - if (!consumeIf('t') && !consumeIf('T')) - return nullptr; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return nullptr; - if (!consumeIf('E')) - return nullptr; - return make<EnclosingExpr>("decltype(", E, ")"); -} - -// <array-type> ::= A <positive dimension number> _ <element type> -// ::= A [<dimension expression>] _ <element type> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() { - if (!consumeIf('A')) - return nullptr; - - NodeOrString Dimension; - - if (std::isdigit(look())) { - Dimension = parseNumber(); - if (!consumeIf('_')) - return nullptr; - } else if (!consumeIf('_')) { - Node *DimExpr = getDerived().parseExpr(); - if (DimExpr == nullptr) - return nullptr; - if (!consumeIf('_')) - return nullptr; - Dimension = DimExpr; - } - - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<ArrayType>(Ty, Dimension); -} - -// <pointer-to-member-type> ::= M <class type> <member type> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() { - if (!consumeIf('M')) - return nullptr; - Node *ClassType = getDerived().parseType(); - if (ClassType == nullptr) - return nullptr; - Node *MemberType = getDerived().parseType(); - if (MemberType == nullptr) - return nullptr; - return make<PointerToMemberType>(ClassType, MemberType); -} - -// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier -// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class' -// ::= Tu <name> # dependent elaborated type specifier using 'union' -// ::= Te <name> # dependent elaborated type specifier using 'enum' -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { - StringView ElabSpef; - if (consumeIf("Ts")) - ElabSpef = "struct"; - else if (consumeIf("Tu")) - ElabSpef = "union"; - else if (consumeIf("Te")) - ElabSpef = "enum"; - - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - - if (!ElabSpef.empty()) - return make<ElaboratedTypeSpefType>(ElabSpef, Name); - - return Name; -} - -// <qualified-type> ::= <qualifiers> <type> -// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers> -// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { - if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); - if (Qual.empty()) - return nullptr; - - // FIXME parse the optional <template-args> here! - - // extension ::= U <objc-name> <objc-type> # objc-type<identifier> - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; - { - SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); - Proto = parseBareSourceName(); - } - if (Proto.empty()) - return nullptr; - Node *Child = getDerived().parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<ObjCProtoName>(Child, Proto); - } - - Node *Child = getDerived().parseQualifiedType(); - if (Child == nullptr) - return nullptr; - return make<VendorExtQualType>(Child, Qual); - } - - Qualifiers Quals = parseCVQualifiers(); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - if (Quals != QualNone) - Ty = make<QualType>(Ty, Quals); - return Ty; -} - -// <type> ::= <builtin-type> -// ::= <qualified-type> -// ::= <function-type> -// ::= <class-enum-type> -// ::= <array-type> -// ::= <pointer-to-member-type> -// ::= <template-param> -// ::= <template-template-param> <template-args> -// ::= <decltype> -// ::= P <type> # pointer -// ::= R <type> # l-value reference -// ::= O <type> # r-value reference (C++11) -// ::= C <type> # complex pair (C99) -// ::= G <type> # imaginary (C99) -// ::= <substitution> # See Compression below -// extension ::= U <objc-name> <objc-type> # objc-type<identifier> -// extension ::= <vector-type> # <vector-type> starts with Dv -// -// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 -// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseType() { - Node *Result = nullptr; - - switch (look()) { - // ::= <qualified-type> - case 'r': - case 'V': - case 'K': { - unsigned AfterQuals = 0; - if (look(AfterQuals) == 'r') ++AfterQuals; - if (look(AfterQuals) == 'V') ++AfterQuals; - if (look(AfterQuals) == 'K') ++AfterQuals; - - if (look(AfterQuals) == 'F' || - (look(AfterQuals) == 'D' && - (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' || - look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) { - Result = getDerived().parseFunctionType(); - break; - } - _LIBCPP_FALLTHROUGH(); - } - case 'U': { - Result = getDerived().parseQualifiedType(); - break; - } - // <builtin-type> ::= v # void - case 'v': - ++First; - return make<NameType>("void"); - // ::= w # wchar_t - case 'w': - ++First; - return make<NameType>("wchar_t"); - // ::= b # bool - case 'b': - ++First; - return make<NameType>("bool"); - // ::= c # char - case 'c': - ++First; - return make<NameType>("char"); - // ::= a # signed char - case 'a': - ++First; - return make<NameType>("signed char"); - // ::= h # unsigned char - case 'h': - ++First; - return make<NameType>("unsigned char"); - // ::= s # short - case 's': - ++First; - return make<NameType>("short"); - // ::= t # unsigned short - case 't': - ++First; - return make<NameType>("unsigned short"); - // ::= i # int - case 'i': - ++First; - return make<NameType>("int"); - // ::= j # unsigned int - case 'j': - ++First; - return make<NameType>("unsigned int"); - // ::= l # long - case 'l': - ++First; - return make<NameType>("long"); - // ::= m # unsigned long - case 'm': - ++First; - return make<NameType>("unsigned long"); - // ::= x # long long, __int64 - case 'x': - ++First; - return make<NameType>("long long"); - // ::= y # unsigned long long, __int64 - case 'y': - ++First; - return make<NameType>("unsigned long long"); - // ::= n # __int128 - case 'n': - ++First; - return make<NameType>("__int128"); - // ::= o # unsigned __int128 - case 'o': - ++First; - return make<NameType>("unsigned __int128"); - // ::= f # float - case 'f': - ++First; - return make<NameType>("float"); - // ::= d # double - case 'd': - ++First; - return make<NameType>("double"); - // ::= e # long double, __float80 - case 'e': - ++First; - return make<NameType>("long double"); - // ::= g # __float128 - case 'g': - ++First; - return make<NameType>("__float128"); - // ::= z # ellipsis - case 'z': - ++First; - return make<NameType>("..."); - - // <builtin-type> ::= u <source-name> # vendor extended type - case 'u': { - ++First; - StringView Res = parseBareSourceName(); - if (Res.empty()) - return nullptr; - return make<NameType>(Res); - } - case 'D': - switch (look(1)) { - // ::= Dd # IEEE 754r decimal floating point (64 bits) - case 'd': - First += 2; - return make<NameType>("decimal64"); - // ::= De # IEEE 754r decimal floating point (128 bits) - case 'e': - First += 2; - return make<NameType>("decimal128"); - // ::= Df # IEEE 754r decimal floating point (32 bits) - case 'f': - First += 2; - return make<NameType>("decimal32"); - // ::= Dh # IEEE 754r half-precision floating point (16 bits) - case 'h': - First += 2; - return make<NameType>("decimal16"); - // ::= Di # char32_t - case 'i': - First += 2; - return make<NameType>("char32_t"); - // ::= Ds # char16_t - case 's': - First += 2; - return make<NameType>("char16_t"); - // ::= Da # auto (in dependent new-expressions) - case 'a': - First += 2; - return make<NameType>("auto"); - // ::= Dc # decltype(auto) - case 'c': - First += 2; - return make<NameType>("decltype(auto)"); - // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) - case 'n': - First += 2; - return make<NameType>("std::nullptr_t"); - - // ::= <decltype> - case 't': - case 'T': { - Result = getDerived().parseDecltype(); - break; - } - // extension ::= <vector-type> # <vector-type> starts with Dv - case 'v': { - Result = getDerived().parseVectorType(); - break; - } - // ::= Dp <type> # pack expansion (C++0x) - case 'p': { - First += 2; - Node *Child = getDerived().parseType(); - if (!Child) - return nullptr; - Result = make<ParameterPackExpansion>(Child); - break; - } - // Exception specifier on a function type. - case 'o': - case 'O': - case 'w': - // Transaction safe function type. - case 'x': - Result = getDerived().parseFunctionType(); - break; - } - break; - // ::= <function-type> - case 'F': { - Result = getDerived().parseFunctionType(); - break; - } - // ::= <array-type> - case 'A': { - Result = getDerived().parseArrayType(); - break; - } - // ::= <pointer-to-member-type> - case 'M': { - Result = getDerived().parsePointerToMemberType(); - break; - } - // ::= <template-param> - case 'T': { - // This could be an elaborate type specifier on a <class-enum-type>. - if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') { - Result = getDerived().parseClassEnumType(); - break; - } - - Result = getDerived().parseTemplateParam(); - if (Result == nullptr) - return nullptr; - - // Result could be either of: - // <type> ::= <template-param> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (TryToParseTemplateArgs && look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Result, TA); - } - break; - } - // ::= P <type> # pointer - case 'P': { - ++First; - Node *Ptr = getDerived().parseType(); - if (Ptr == nullptr) - return nullptr; - Result = make<PointerType>(Ptr); - break; - } - // ::= R <type> # l-value reference - case 'R': { - ++First; - Node *Ref = getDerived().parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::LValue); - break; - } - // ::= O <type> # r-value reference (C++11) - case 'O': { - ++First; - Node *Ref = getDerived().parseType(); - if (Ref == nullptr) - return nullptr; - Result = make<ReferenceType>(Ref, ReferenceKind::RValue); - break; - } - // ::= C <type> # complex pair (C99) - case 'C': { - ++First; - Node *P = getDerived().parseType(); - if (P == nullptr) - return nullptr; - Result = make<PostfixQualifiedType>(P, " complex"); - break; - } - // ::= G <type> # imaginary (C99) - case 'G': { - ++First; - Node *P = getDerived().parseType(); - if (P == nullptr) - return P; - Result = make<PostfixQualifiedType>(P, " imaginary"); - break; - } - // ::= <substitution> # See Compression below - case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) - return nullptr; - - // Sub could be either of: - // <type> ::= <substitution> - // <type> ::= <template-template-param> <template-args> - // - // <template-template-param> ::= <template-param> - // ::= <substitution> - // - // If this is followed by some <template-args>, and we're permitted to - // parse them, take the second production. - - if (TryToParseTemplateArgs && look() == 'I') { - Node *TA = getDerived().parseTemplateArgs(); - if (TA == nullptr) - return nullptr; - Result = make<NameWithTemplateArgs>(Sub, TA); - break; - } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; - } - _LIBCPP_FALLTHROUGH(); - } - // ::= <class-enum-type> - default: { - Result = getDerived().parseClassEnumType(); - break; - } - } - - // If we parsed a type, insert it into the substitution table. Note that all - // <builtin-type>s and <substitution>s have already bailed out, because they - // don't get substitutions. - if (Result != nullptr) - Subs.push_back(Result); - return Result; -} - -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return nullptr; - return make<PrefixExpr>(Kind, E); -} - -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) { - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<BinaryExpr>(LHS, Kind, RHS); -} - -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); - if (!Tmp.empty() && consumeIf('E')) - return make<IntegerLiteral>(Lit, Tmp); - return nullptr; -} - -// <CV-Qualifiers> ::= [r] [V] [K] -template <typename Alloc, typename Derived> -Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() { - Qualifiers CVR = QualNone; - if (consumeIf('r')) - CVR |= QualRestrict; - if (consumeIf('V')) - CVR |= QualVolatile; - if (consumeIf('K')) - CVR |= QualConst; - return CVR; -} - -// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { - if (consumeIf("fp")) { - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - if (consumeIf("fL")) { - if (parseNumber().empty()) - return nullptr; - if (!consumeIf('p')) - return nullptr; - parseCVQualifiers(); - StringView Num = parseNumber(); - if (!consumeIf('_')) - return nullptr; - return make<FunctionParam>(Num); - } - return nullptr; -} - -// [gs] nw <expression>* _ <type> E # new (expr-list) type -// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// [gs] na <expression>* _ <type> E # new[] (expr-list) type -// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// <initializer> ::= pi <expression>* E # parenthesized initialization -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray); -} - -// cv <type> <expression> # conversion with one argument -// cv <type> _ <expression>* E # conversion with a different number of arguments -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() { - if (!consumeIf("cv")) - return nullptr; - Node *Ty; - { - SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); - Ty = getDerived().parseType(); - } - - if (Ty == nullptr) - return nullptr; - - if (consumeIf('_')) { - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - NodeArray Exprs = popTrailingNodeArray(ExprsBegin); - return make<ConversionExpr>(Ty, Exprs); - } - - Node *E[1] = {getDerived().parseExpr()}; - if (E[0] == nullptr) - return nullptr; - return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1)); -} - -// <expr-primary> ::= L <type> <value number> E # integer literal -// ::= L <type> <value float> E # floating literal -// ::= L <string type> E # string literal -// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") -// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) -// ::= L <mangled-name> E # external name -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { - if (!consumeIf('L')) - return nullptr; - switch (look()) { - case 'w': - ++First; - return getDerived().parseIntegerLiteral("wchar_t"); - case 'b': - if (consumeIf("b0E")) - return make<BoolExpr>(0); - if (consumeIf("b1E")) - return make<BoolExpr>(1); - return nullptr; - case 'c': - ++First; - return getDerived().parseIntegerLiteral("char"); - case 'a': - ++First; - return getDerived().parseIntegerLiteral("signed char"); - case 'h': - ++First; - return getDerived().parseIntegerLiteral("unsigned char"); - case 's': - ++First; - return getDerived().parseIntegerLiteral("short"); - case 't': - ++First; - return getDerived().parseIntegerLiteral("unsigned short"); - case 'i': - ++First; - return getDerived().parseIntegerLiteral(""); - case 'j': - ++First; - return getDerived().parseIntegerLiteral("u"); - case 'l': - ++First; - return getDerived().parseIntegerLiteral("l"); - case 'm': - ++First; - return getDerived().parseIntegerLiteral("ul"); - case 'x': - ++First; - return getDerived().parseIntegerLiteral("ll"); - case 'y': - ++First; - return getDerived().parseIntegerLiteral("ull"); - case 'n': - ++First; - return getDerived().parseIntegerLiteral("__int128"); - case 'o': - ++First; - return getDerived().parseIntegerLiteral("unsigned __int128"); - case 'f': - ++First; - return getDerived().template parseFloatingLiteral<float>(); - case 'd': - ++First; - return getDerived().template parseFloatingLiteral<double>(); - case 'e': - ++First; - return getDerived().template parseFloatingLiteral<long double>(); - case '_': - if (consumeIf("_Z")) { - Node *R = getDerived().parseEncoding(); - if (R != nullptr && consumeIf('E')) - return R; - } - return nullptr; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - return nullptr; - default: { - // might be named type - Node *T = getDerived().parseType(); - if (T == nullptr) - return nullptr; - StringView N = parseNumber(); - if (!N.empty()) { - if (!consumeIf('E')) - return nullptr; - return make<IntegerCastExpr>(T, N); - } - if (consumeIf('E')) - return T; - return nullptr; - } - } -} - -// <braced-expression> ::= <expression> -// ::= di <field source-name> <braced-expression> # .name = expr -// ::= dx <index expression> <braced-expression> # [expr] = expr -// ::= dX <range begin expression> <range end expression> <braced-expression> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBracedExpr() { - if (look() == 'd') { - switch (look(1)) { - case 'i': { - First += 2; - Node *Field = getDerived().parseSourceName(/*NameState=*/nullptr); - if (Field == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Field, Init, /*isArray=*/false); - } - case 'x': { - First += 2; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedExpr>(Index, Init, /*isArray=*/true); - } - case 'X': { - First += 2; - Node *RangeBegin = getDerived().parseExpr(); - if (RangeBegin == nullptr) - return nullptr; - Node *RangeEnd = getDerived().parseExpr(); - if (RangeEnd == nullptr) - return nullptr; - Node *Init = getDerived().parseBracedExpr(); - if (Init == nullptr) - return nullptr; - return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init); - } - } - } - return getDerived().parseExpr(); -} - -// (not yet in the spec) -// <fold-expr> ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { - if (!consumeIf('f')) - return nullptr; - - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else - return nullptr; - ++First; - - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; - - Node *Pack = getDerived().parseExpr(), *Init = nullptr; - if (Pack == nullptr) - return nullptr; - if (HasInitializer) { - Init = getDerived().parseExpr(); - if (Init == nullptr) - return nullptr; - } - - if (IsLeftFold && Init) - std::swap(Pack, Init); - - return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init); -} - -// <expression> ::= <unary operator-name> <expression> -// ::= <binary operator-name> <expression> <expression> -// ::= <ternary operator-name> <expression> <expression> <expression> -// ::= cl <expression>+ E # call -// ::= cv <type> <expression> # conversion with one argument -// ::= cv <type> _ <expression>* E # conversion with a different number of arguments -// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type -// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type -// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// ::= [gs] dl <expression> # delete expression -// ::= [gs] da <expression> # delete[] expression -// ::= pp_ <expression> # prefix ++ -// ::= mm_ <expression> # prefix -- -// ::= ti <type> # typeid (type) -// ::= te <expression> # typeid (expression) -// ::= dc <type> <expression> # dynamic_cast<type> (expression) -// ::= sc <type> <expression> # static_cast<type> (expression) -// ::= cc <type> <expression> # const_cast<type> (expression) -// ::= rc <type> <expression> # reinterpret_cast<type> (expression) -// ::= st <type> # sizeof (a type) -// ::= sz <expression> # sizeof (an expression) -// ::= at <type> # alignof (a type) -// ::= az <expression> # alignof (an expression) -// ::= nx <expression> # noexcept (expression) -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> # expr.name -// ::= pt <expression> <unresolved-name> # expr->name -// ::= ds <expression> <expression> # expr.*expr -// ::= sZ <template-param> # size of a parameter pack -// ::= sZ <function-param> # size of a function parameter pack -// ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template -// ::= sp <expression> # pack expansion -// ::= tw <expression> # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= <unresolved-name> # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= fL <binary-operator-name> <expression> <expression> -// ::= fR <binary-operator-name> <expression> <expression> -// ::= fl <binary-operator-name> <expression> -// ::= fr <binary-operator-name> <expression> -// ::= <expr-primary> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { - bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - - switch (*First) { - case 'L': - return getDerived().parseExprPrimary(); - case 'T': - return getDerived().parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a <function-param>. - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return getDerived().parseBinaryExpr("&&"); - case 'd': - First += 2; - return getDerived().parsePrefixExpr("&"); - case 'n': - First += 2; - return getDerived().parseBinaryExpr("&"); - case 'N': - First += 2; - return getDerived().parseBinaryExpr("&="); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ty = getDerived().parseExpr(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc <type> <expression> # const_cast<type>(expression) - case 'c': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("const_cast", Ty, Ex); - } - // cl <expression>+ E # call - case 'l': { - First += 2; - Node *Callee = getDerived().parseExpr(); - if (Callee == nullptr) - return Callee; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr(","); - case 'o': - First += 2; - return getDerived().parsePrefixExpr("~"); - case 'v': - return getDerived().parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<DeleteExpr>(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return getDerived().parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - return make<DeleteExpr>(E, Global, /*is_array=*/false); - } - case 'n': - return getDerived().parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<MemberExpr>(LHS, ".*", RHS); - } - case 't': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return LHS; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<MemberExpr>(LHS, ".", RHS); - } - case 'v': - First += 2; - return getDerived().parseBinaryExpr("/"); - case 'V': - First += 2; - return getDerived().parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return getDerived().parseBinaryExpr("^"); - case 'O': - First += 2; - return getDerived().parseBinaryExpr("^="); - case 'q': - First += 2; - return getDerived().parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr(">="); - case 't': - First += 2; - return getDerived().parseBinaryExpr(">"); - } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; - Node *Base = getDerived().parseExpr(); - if (Base == nullptr) - return nullptr; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return Index; - return make<ArraySubscriptExpr>(Base, Index); - } - case 'l': { - First += 2; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); - } - } - return nullptr; - case 'l': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr("<="); - case 's': - First += 2; - return getDerived().parseBinaryExpr("<<"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("<<="); - case 't': - First += 2; - return getDerived().parseBinaryExpr("<"); - } - return nullptr; - case 'm': - switch (First[1]) { - case 'i': - First += 2; - return getDerived().parseBinaryExpr("-"); - case 'I': - First += 2; - return getDerived().parseBinaryExpr("-="); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("*"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("*="); - case 'm': - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("--"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<PostfixExpr>(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return getDerived().parseNewExpr(); - case 'e': - First += 2; - return getDerived().parseBinaryExpr("!="); - case 'g': - First += 2; - return getDerived().parsePrefixExpr("-"); - case 't': - First += 2; - return getDerived().parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("noexcept (", Ex, ")"); - } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return getDerived().parseUnresolvedName(); - case 'o': - First += 2; - return getDerived().parseBinaryExpr("||"); - case 'r': - First += 2; - return getDerived().parseBinaryExpr("|"); - case 'R': - First += 2; - return getDerived().parseBinaryExpr("|="); - } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return getDerived().parseBinaryExpr("->*"); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("+"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("++"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<PostfixExpr>(Ex, "++"); - } - case 's': - First += 2; - return getDerived().parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = getDerived().parseExpr(); - if (L == nullptr) - return nullptr; - Node *R = getDerived().parseExpr(); - if (R == nullptr) - return nullptr; - return make<MemberExpr>(L, "->", R); - } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; - Node *Cond = getDerived().parseExpr(); - if (Cond == nullptr) - return nullptr; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) - return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) - return nullptr; - return make<ConditionalExpr>(Cond, LHS, RHS); - } - return nullptr; - case 'r': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("reinterpret_cast", T, Ex); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr("%"); - case 'M': - First += 2; - return getDerived().parseBinaryExpr("%="); - case 's': - First += 2; - return getDerived().parseBinaryExpr(">>"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("static_cast", T, Ex); - } - case 'p': { - First += 2; - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make<ParameterPackExpansion>(Child); - } - case 'r': - return getDerived().parseUnresolvedName(); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("sizeof (", Ex, ")"); - } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make<SizeofParamPackExpr>(R); - } else if (look() == 'f') { - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make<EnclosingExpr>("sizeof... (", FP, ")"); - } - return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); - if (!Pack) - return nullptr; - return make<EnclosingExpr>("sizeof... (", Pack, ")"); - } - } - return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("typeid (", Ex, ")"); - } - case 'i': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("typeid (", Ty, ")"); - } - case 'l': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); - } - case 'r': - First += 2; - return make<NameType>("throw"); - case 'w': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - return make<ThrowExpr>(Ex); - } - } - return nullptr; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return getDerived().parseUnresolvedName(); - } - return nullptr; -} - -// <call-offset> ::= h <nv-offset> _ -// ::= v <v-offset> _ -// -// <nv-offset> ::= <offset number> -// # non-virtual base override -// -// <v-offset> ::= <offset number> _ <virtual offset number> -// # virtual base override, with vcall offset -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() { - // Just scan through the call offset, we never add this information into the - // output. - if (consumeIf('h')) - return parseNumber(true).empty() || !consumeIf('_'); - if (consumeIf('v')) - return parseNumber(true).empty() || !consumeIf('_') || - parseNumber(true).empty() || !consumeIf('_'); - return true; -} - -// <special-name> ::= TV <type> # virtual table -// ::= TT <type> # VTT structure (construction vtable index) -// ::= TI <type> # typeinfo structure -// ::= TS <type> # typeinfo name (null-terminated byte string) -// ::= Tc <call-offset> <call-offset> <base encoding> -// # base is the nominal target function of thunk -// # first call-offset is 'this' adjustment -// # second call-offset is result adjustment -// ::= T <call-offset> <base encoding> -// # base is the nominal target function of thunk -// ::= GV <object name> # Guard variable for one-time initialization -// # No <type> -// ::= TW <object name> # Thread-local wrapper -// ::= TH <object name> # Thread-local initialization -// ::= GR <object name> _ # First temporary -// ::= GR <object name> <seq-id> _ # Subsequent temporaries -// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first -// extension ::= GR <object name> # reference temporary for object -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { - switch (look()) { - case 'T': - switch (look(1)) { - // TV <type> # virtual table - case 'V': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("vtable for ", Ty); - } - // TT <type> # VTT structure (construction vtable index) - case 'T': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("VTT for ", Ty); - } - // TI <type> # typeinfo structure - case 'I': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo for ", Ty); - } - // TS <type> # typeinfo name (null-terminated byte string) - case 'S': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<SpecialName>("typeinfo name for ", Ty); - } - // Tc <call-offset> <call-offset> <base encoding> - case 'c': { - First += 2; - if (parseCallOffset() || parseCallOffset()) - return nullptr; - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr) - return nullptr; - return make<SpecialName>("covariant return thunk to ", Encoding); - } - // extension ::= TC <first type> <number> _ <second type> - // # construction vtable for second-in-first - case 'C': { - First += 2; - Node *FirstType = getDerived().parseType(); - if (FirstType == nullptr) - return nullptr; - if (parseNumber(true).empty() || !consumeIf('_')) - return nullptr; - Node *SecondType = getDerived().parseType(); - if (SecondType == nullptr) - return nullptr; - return make<CtorVtableSpecialName>(SecondType, FirstType); - } - // TW <object name> # Thread-local wrapper - case 'W': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local wrapper routine for ", Name); - } - // TH <object name> # Thread-local initialization - case 'H': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("thread-local initialization routine for ", Name); - } - // T <call-offset> <base encoding> - default: { - ++First; - bool IsVirt = look() == 'v'; - if (parseCallOffset()) - return nullptr; - Node *BaseEncoding = getDerived().parseEncoding(); - if (BaseEncoding == nullptr) - return nullptr; - if (IsVirt) - return make<SpecialName>("virtual thunk to ", BaseEncoding); - else - return make<SpecialName>("non-virtual thunk to ", BaseEncoding); - } - } - case 'G': - switch (look(1)) { - // GV <object name> # Guard variable for one-time initialization - case 'V': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - return make<SpecialName>("guard variable for ", Name); - } - // GR <object name> # reference temporary for object - // GR <object name> _ # First temporary - // GR <object name> <seq-id> _ # Subsequent temporaries - case 'R': { - First += 2; - Node *Name = getDerived().parseName(); - if (Name == nullptr) - return nullptr; - size_t Count; - bool ParsedSeqId = !parseSeqId(&Count); - if (!consumeIf('_') && ParsedSeqId) - return nullptr; - return make<SpecialName>("reference temporary for ", Name); - } - } - } - return nullptr; -} - -// <encoding> ::= <function name> <bare-function-type> -// ::= <data name> -// ::= <special-name> -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { - if (look() == 'G' || look() == 'T') - return getDerived().parseSpecialName(); - - auto IsEndOfEncoding = [&] { - // The set of chars that can potentially follow an <encoding> (none of which - // can start a <type>). Enumerating these allows us to avoid speculative - // parsing. - return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_'; - }; - - NameState NameInfo(this); - Node *Name = getDerived().parseName(&NameInfo); - if (Name == nullptr) - return nullptr; - - if (resolveForwardTemplateRefs(NameInfo)) - return nullptr; - - if (IsEndOfEncoding()) - return Name; - - Node *Attrs = nullptr; - if (consumeIf("Ua9enable_ifI")) { - size_t BeforeArgs = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs)); - if (!Attrs) - return nullptr; - } - - Node *ReturnType = nullptr; - if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) { - ReturnType = getDerived().parseType(); - if (ReturnType == nullptr) - return nullptr; - } - - if (consumeIf('v')) - return make<FunctionEncoding>(ReturnType, Name, NodeArray(), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); - - size_t ParamsBegin = Names.size(); - do { - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - Names.push_back(Ty); - } while (!IsEndOfEncoding()); - - return make<FunctionEncoding>(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); -} - -template <class Float> -struct FloatData; - -template <> -struct FloatData<float> -{ - static const size_t mangled_size = 8; - static const size_t max_demangled_size = 24; - static constexpr const char* spec = "%af"; -}; - -template <> -struct FloatData<double> -{ - static const size_t mangled_size = 16; - static const size_t max_demangled_size = 32; - static constexpr const char* spec = "%a"; -}; - -template <> -struct FloatData<long double> -{ -#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) - static const size_t mangled_size = 32; -#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) - 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"; -}; - -template <typename Alloc, typename Derived> -template <class Float> -Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() { - const size_t N = FloatData<Float>::mangled_size; - if (numLeft() <= N) - return nullptr; - StringView Data(First, First + N); - for (char C : Data) - if (!std::isxdigit(C)) - return nullptr; - First += N; - if (!consumeIf('E')) - return nullptr; - return make<FloatLiteralImpl<Float>>(Data); -} - -// <seq-id> ::= <0-9A-Z>+ -template <typename Alloc, typename Derived> -bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) { - if (!(look() >= '0' && look() <= '9') && - !(look() >= 'A' && look() <= 'Z')) - return true; - - size_t Id = 0; - while (true) { - if (look() >= '0' && look() <= '9') { - Id *= 36; - Id += static_cast<size_t>(look() - '0'); - } else if (look() >= 'A' && look() <= 'Z') { - Id *= 36; - Id += static_cast<size_t>(look() - 'A') + 10; - } else { - *Out = Id; - return false; - } - ++First; - } -} - -// <substitution> ::= S <seq-id> _ -// ::= S_ -// <substitution> ::= Sa # ::std::allocator -// <substitution> ::= Sb # ::std::basic_string -// <substitution> ::= Ss # ::std::basic_string < char, -// ::std::char_traits<char>, -// ::std::allocator<char> > -// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > -// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > -// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { - if (!consumeIf('S')) - return nullptr; - - if (std::islower(look())) { - Node *SpecialSub; - switch (look()) { - case 'a': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator); - break; - case 'b': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string); - break; - case 's': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string); - break; - case 'i': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream); - break; - case 'o': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream); - break; - case 'd': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream); - break; - default: - return nullptr; - } - if (!SpecialSub) - return nullptr; - // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> - // has ABI tags, the tags are appended to the substitution; the result is a - // substitutable component. - Node *WithTags = getDerived().parseAbiTags(SpecialSub); - if (WithTags != SpecialSub) { - Subs.push_back(WithTags); - SpecialSub = WithTags; - } - return SpecialSub; - } - - // ::= S_ - if (consumeIf('_')) { - if (Subs.empty()) - return nullptr; - return Subs[0]; - } - - // ::= S <seq-id> _ - size_t Index = 0; - if (parseSeqId(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_') || Index >= Subs.size()) - return nullptr; - return Subs[Index]; -} - -// <template-param> ::= T_ # first template parameter -// ::= T <parameter-2 non-negative number> _ -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { - if (!consumeIf('T')) - return nullptr; - - size_t Index = 0; - if (!consumeIf('_')) { - if (parsePositiveInteger(&Index)) - return nullptr; - ++Index; - if (!consumeIf('_')) - return nullptr; - } - - // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list - // are mangled as the corresponding artificial template type parameter. - if (ParsingLambdaParams) - return make<NameType>("auto"); - - // If we're in a context where this <template-param> refers to a - // <template-arg> further ahead in the mangled name (currently just conversion - // operator types), then we should only look it up in the right context. - if (PermitForwardTemplateReferences) { - Node *ForwardRef = make<ForwardTemplateReference>(Index); - if (!ForwardRef) - return nullptr; - assert(ForwardRef->getKind() == Node::KForwardTemplateReference); - ForwardTemplateRefs.push_back( - static_cast<ForwardTemplateReference *>(ForwardRef)); - return ForwardRef; - } - - if (Index >= TemplateParams.size()) - return nullptr; - return TemplateParams[Index]; -} - -// <template-arg> ::= <type> # type or template -// ::= X <expression> E # expression -// ::= <expr-primary> # simple expressions -// ::= J <template-arg>* E # argument pack -// ::= LZ <encoding> E # extension -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() { - switch (look()) { - case 'X': { - ++First; - Node *Arg = getDerived().parseExpr(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - case 'J': { - ++First; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - NodeArray Args = popTrailingNodeArray(ArgsBegin); - return make<TemplateArgumentPack>(Args); - } - case 'L': { - // ::= LZ <encoding> E # extension - if (look(1) == 'Z') { - First += 2; - Node *Arg = getDerived().parseEncoding(); - if (Arg == nullptr || !consumeIf('E')) - return nullptr; - return Arg; - } - // ::= <expr-primary> # simple expressions - return getDerived().parseExprPrimary(); - } - default: - return getDerived().parseType(); - } -} - -// <template-args> ::= I <template-arg>* E -// extension, the abi says <template-arg>+ -template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { - if (!consumeIf('I')) - return nullptr; - - // <template-params> refer to the innermost <template-args>. Clear out any - // outer args that we may have inserted into TemplateParams. - if (TagTemplates) - TemplateParams.clear(); - - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - if (TagTemplates) { - auto OldParams = std::move(TemplateParams); - Node *Arg = getDerived().parseTemplateArg(); - TemplateParams = std::move(OldParams); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - Node *TableEntry = Arg; - if (Arg->getKind() == Node::KTemplateArgumentPack) { - TableEntry = make<ParameterPack>( - static_cast<TemplateArgumentPack*>(TableEntry)->getElements()); - if (!TableEntry) - return nullptr; - } - TemplateParams.push_back(TableEntry); - } else { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - } - return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); -} - -// <mangled-name> ::= _Z <encoding> -// ::= <type> -// extension ::= ___Z <encoding> _block_invoke -// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+ -// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+ -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parse() { - if (consumeIf("_Z")) { - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr) - return nullptr; - if (look() == '.') { - Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); - First = Last; - } - if (numLeft() != 0) - return nullptr; - return Encoding; - } - - if (consumeIf("___Z")) { - Node *Encoding = getDerived().parseEncoding(); - if (Encoding == nullptr || !consumeIf("_block_invoke")) - return nullptr; - bool RequireNumber = consumeIf('_'); - if (parseNumber().empty() && RequireNumber) - return nullptr; - if (look() == '.') - First = Last; - if (numLeft() != 0) - return nullptr; - return make<SpecialName>("invocation function for block in ", Encoding); - } - - Node *Ty = getDerived().parseType(); - if (numLeft() != 0) - return nullptr; - return Ty; -} - -template <typename Alloc> -struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> { - using AbstractManglingParser<ManglingParser<Alloc>, - Alloc>::AbstractManglingParser; -}; - -} // namespace itanium_demangle -} // namespace - -#endif // LIBCXX_DEMANGLE_ITANIUMDEMANGLE_H diff --git a/lib/libcxxabi/src/demangle/StringView.h b/lib/libcxxabi/src/demangle/StringView.h deleted file mode 100644 index 986f2defc08..00000000000 --- a/lib/libcxxabi/src/demangle/StringView.h +++ /dev/null @@ -1,98 +0,0 @@ -//===--- StringView.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// -// This file is copied from llvm/lib/Demangle/StringView.h. -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_STRINGVIEW_H -#define LIBCXX_DEMANGLE_STRINGVIEW_H - -#include <algorithm> -#include <cassert> -#include <cstring> - -namespace { -class StringView { - const char *First; - const char *Last; - -public: - template <size_t N> - StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {} - StringView(const char *First_, const char *Last_) - : First(First_), Last(Last_) {} - StringView(const char *First_, size_t Len) - : First(First_), Last(First_ + Len) {} - StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} - StringView() : First(nullptr), Last(nullptr) {} - - StringView substr(size_t From) const { - return StringView(begin() + From, size() - From); - } - - StringView substr(size_t From, size_t To) const { - if (To >= size()) - To = size() - 1; - if (From >= size()) - From = size() - 1; - return StringView(First + From, First + To); - } - - StringView dropFront(size_t N = 1) const { - if (N >= size()) - N = size() - 1; - return StringView(First + N, Last); - } - - char front() const { - assert(!empty()); - return *begin(); - } - - char popFront() { - assert(!empty()); - return *First++; - } - - bool consumeFront(char C) { - if (!startsWith(C)) - return false; - *this = dropFront(1); - return true; - } - - bool consumeFront(StringView S) { - if (!startsWith(S)) - return false; - *this = dropFront(S.size()); - return true; - } - - bool startsWith(char C) const { return !empty() && *begin() == C; } - - bool startsWith(StringView Str) const { - if (Str.size() > size()) - return false; - return std::equal(Str.begin(), Str.end(), begin()); - } - - const char &operator[](size_t Idx) const { return *(begin() + Idx); } - - const char *begin() const { return First; } - const char *end() const { return Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - bool empty() const { return First == Last; } -}; - -inline bool operator==(const StringView &LHS, const StringView &RHS) { - return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); -} -} // namespace - -#endif diff --git a/lib/libcxxabi/src/demangle/Utility.h b/lib/libcxxabi/src/demangle/Utility.h deleted file mode 100644 index b5e9b5e42cf..00000000000 --- a/lib/libcxxabi/src/demangle/Utility.h +++ /dev/null @@ -1,190 +0,0 @@ -//===--- Utility.h ----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// -// This file is copied from llvm/lib/Demangle/Utility.h. -//===----------------------------------------------------------------------===// - -#ifndef LIBCXX_DEMANGLE_UTILITY_H -#define LIBCXX_DEMANGLE_UTILITY_H - -#include "StringView.h" - -#include <cstdint> -#include <cstdlib> -#include <cstring> -#include <iterator> -#include <limits> - -namespace { -// Stream that AST nodes write their string representation into after the AST -// has been parsed. -class OutputStream { - char *Buffer; - size_t CurrentPosition; - size_t BufferCapacity; - - // Ensure there is at least n more positions in buffer. - void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { - BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; - Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); - if (Buffer == nullptr) - std::terminate(); - } - } - - void writeUnsigned(uint64_t N, bool isNeg = false) { - // Handle special case... - if (N == 0) { - *this << '0'; - return; - } - - char Temp[21]; - char *TempPtr = std::end(Temp); - - while (N) { - *--TempPtr = '0' + char(N % 10); - N /= 10; - } - - // Add negative sign... - if (isNeg) - *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); - } - -public: - OutputStream(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; - void reset(char *Buffer_, size_t BufferCapacity_) { - CurrentPosition = 0; - Buffer = Buffer_; - BufferCapacity = BufferCapacity_; - } - - /// If a ParameterPackExpansion (or similar type) is encountered, the offset - /// into the pack that we're currently printing. - unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); - unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); - - OutputStream &operator+=(StringView R) { - size_t Size = R.size(); - if (Size == 0) - return *this; - grow(Size); - std::memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; - return *this; - } - - OutputStream &operator+=(char C) { - grow(1); - Buffer[CurrentPosition++] = C; - return *this; - } - - OutputStream &operator<<(StringView R) { return (*this += R); } - - OutputStream &operator<<(char C) { return (*this += C); } - - OutputStream &operator<<(long long N) { - if (N < 0) - writeUnsigned(static_cast<unsigned long long>(-N), true); - else - writeUnsigned(static_cast<unsigned long long>(N)); - return *this; - } - - OutputStream &operator<<(unsigned long long N) { - writeUnsigned(N, false); - return *this; - } - - OutputStream &operator<<(long N) { - return this->operator<<(static_cast<long long>(N)); - } - - OutputStream &operator<<(unsigned long N) { - return this->operator<<(static_cast<unsigned long long>(N)); - } - - OutputStream &operator<<(int N) { - return this->operator<<(static_cast<long long>(N)); - } - - OutputStream &operator<<(unsigned int N) { - return this->operator<<(static_cast<unsigned long long>(N)); - } - - size_t getCurrentPosition() const { return CurrentPosition; } - void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } - - char back() const { - return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; - } - - bool empty() const { return CurrentPosition == 0; } - - char *getBuffer() { return Buffer; } - char *getBufferEnd() { return Buffer + CurrentPosition - 1; } - size_t getBufferCapacity() { return BufferCapacity; } -}; - -template <class T> class SwapAndRestore { - T &Restore; - T OriginalValue; - bool ShouldRestore = true; - -public: - SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} - - SwapAndRestore(T &Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); - } - ~SwapAndRestore() { - if (ShouldRestore) - Restore = std::move(OriginalValue); - } - - void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } - - void restoreNow(bool Force) { - if (!Force && !ShouldRestore) - return; - - Restore = std::move(OriginalValue); - ShouldRestore = false; - } - - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; -}; - -inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S, - size_t InitSize) { - size_t BufferSize; - if (Buf == nullptr) { - Buf = static_cast<char *>(std::malloc(InitSize)); - if (Buf == nullptr) - return false; - BufferSize = InitSize; - } else - BufferSize = *N; - - S.reset(Buf, BufferSize); - return true; -} - -} // namespace - -#endif diff --git a/lib/libcxxabi/src/fallback_malloc.cpp b/lib/libcxxabi/src/fallback_malloc.cpp deleted file mode 100644 index 202a46732a3..00000000000 --- a/lib/libcxxabi/src/fallback_malloc.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===------------------------ fallback_malloc.cpp -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION -// is only defined when libc aligned allocation is not available. -#define _LIBCPP_BUILDING_LIBRARY -#include "fallback_malloc.h" - -#include <__threading_support> - -#include <cstdlib> // for malloc, calloc, free -#include <cstring> // for memset - -// A small, simple heap manager based (loosely) on -// the startup heap manager from FreeBSD, optimized for space. -// -// Manages a fixed-size memory pool, supports malloc and free only. -// No support for realloc. -// -// Allocates chunks in multiples of four bytes, with a four byte header -// for each chunk. The overhead of each chunk is kept low by keeping pointers -// as two byte offsets within the heap, rather than (4 or 8 byte) pointers. - -namespace { - -// When POSIX threads are not available, make the mutex operations a nop -#ifndef _LIBCXXABI_HAS_NO_THREADS -_LIBCPP_SAFE_STATIC -static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER; -#else -static void* heap_mutex = 0; -#endif - -class mutexor { -public: -#ifndef _LIBCXXABI_HAS_NO_THREADS - mutexor(std::__libcpp_mutex_t* m) : mtx_(m) { - std::__libcpp_mutex_lock(mtx_); - } - ~mutexor() { std::__libcpp_mutex_unlock(mtx_); } -#else - mutexor(void*) {} - ~mutexor() {} -#endif -private: - mutexor(const mutexor& rhs); - mutexor& operator=(const mutexor& rhs); -#ifndef _LIBCXXABI_HAS_NO_THREADS - std::__libcpp_mutex_t* mtx_; -#endif -}; - -static const size_t HEAP_SIZE = 512; -char heap[HEAP_SIZE] __attribute__((aligned)); - -typedef unsigned short heap_offset; -typedef unsigned short heap_size; - -struct heap_node { - heap_offset next_node; // offset into heap - heap_size len; // size in units of "sizeof(heap_node)" -}; - -static const heap_node* list_end = - (heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap -static heap_node* freelist = NULL; - -heap_node* node_from_offset(const heap_offset offset) { - return (heap_node*)(heap + (offset * sizeof(heap_node))); -} - -heap_offset offset_from_node(const heap_node* ptr) { - return static_cast<heap_offset>( - static_cast<size_t>(reinterpret_cast<const char*>(ptr) - heap) / - sizeof(heap_node)); -} - -void init_heap() { - freelist = (heap_node*)heap; - freelist->next_node = offset_from_node(list_end); - freelist->len = HEAP_SIZE / sizeof(heap_node); -} - -// How big a chunk we allocate -size_t alloc_size(size_t len) { - return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; -} - -bool is_fallback_ptr(void* ptr) { - return ptr >= heap && ptr < (heap + HEAP_SIZE); -} - -void* fallback_malloc(size_t len) { - heap_node *p, *prev; - const size_t nelems = alloc_size(len); - mutexor mtx(&heap_mutex); - - if (NULL == freelist) - init_heap(); - - // Walk the free list, looking for a "big enough" chunk - for (p = freelist, prev = 0; p && p != list_end; - prev = p, p = node_from_offset(p->next_node)) { - - if (p->len > nelems) { // chunk is larger, shorten, and return the tail - heap_node* q; - - p->len = static_cast<heap_size>(p->len - nelems); - q = p + p->len; - q->next_node = 0; - q->len = static_cast<heap_size>(nelems); - return (void*)(q + 1); - } - - if (p->len == nelems) { // exact size match - if (prev == 0) - freelist = node_from_offset(p->next_node); - else - prev->next_node = p->next_node; - p->next_node = 0; - return (void*)(p + 1); - } - } - return NULL; // couldn't find a spot big enough -} - -// Return the start of the next block -heap_node* after(struct heap_node* p) { return p + p->len; } - -void fallback_free(void* ptr) { - struct heap_node* cp = ((struct heap_node*)ptr) - 1; // retrieve the chunk - struct heap_node *p, *prev; - - mutexor mtx(&heap_mutex); - -#ifdef DEBUG_FALLBACK_MALLOC - std::cout << "Freeing item at " << offset_from_node(cp) << " of size " - << cp->len << std::endl; -#endif - - for (p = freelist, prev = 0; p && p != list_end; - prev = p, p = node_from_offset(p->next_node)) { -#ifdef DEBUG_FALLBACK_MALLOC - std::cout << " p, cp, after (p), after(cp) " << offset_from_node(p) << ' ' - << offset_from_node(cp) << ' ' << offset_from_node(after(p)) - << ' ' << offset_from_node(after(cp)) << std::endl; -#endif - if (after(p) == cp) { -#ifdef DEBUG_FALLBACK_MALLOC - std::cout << " Appending onto chunk at " << offset_from_node(p) - << std::endl; -#endif - p->len = static_cast<heap_size>( - p->len + cp->len); // make the free heap_node larger - return; - } else if (after(cp) == p) { // there's a free heap_node right after -#ifdef DEBUG_FALLBACK_MALLOC - std::cout << " Appending free chunk at " << offset_from_node(p) - << std::endl; -#endif - cp->len = static_cast<heap_size>(cp->len + p->len); - if (prev == 0) { - freelist = cp; - cp->next_node = p->next_node; - } else - prev->next_node = offset_from_node(cp); - return; - } - } -// Nothing to merge with, add it to the start of the free list -#ifdef DEBUG_FALLBACK_MALLOC - std::cout << " Making new free list entry " << offset_from_node(cp) - << std::endl; -#endif - cp->next_node = offset_from_node(freelist); - freelist = cp; -} - -#ifdef INSTRUMENT_FALLBACK_MALLOC -size_t print_free_list() { - struct heap_node *p, *prev; - heap_size total_free = 0; - if (NULL == freelist) - init_heap(); - - for (p = freelist, prev = 0; p && p != list_end; - prev = p, p = node_from_offset(p->next_node)) { - std::cout << (prev == 0 ? "" : " ") << "Offset: " << offset_from_node(p) - << "\tsize: " << p->len << " Next: " << p->next_node << std::endl; - total_free += p->len; - } - std::cout << "Total Free space: " << total_free << std::endl; - return total_free; -} -#endif -} // end unnamed namespace - -namespace __cxxabiv1 { - -struct __attribute__((aligned)) __aligned_type {}; - -void* __aligned_malloc_with_fallback(size_t size) { -#if defined(_WIN32) - if (void* dest = _aligned_malloc(size, alignof(__aligned_type))) - return dest; -#elif defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) - if (void* dest = std::malloc(size)) - return dest; -#else - if (size == 0) - size = 1; - void* dest; - if (::posix_memalign(&dest, __alignof(__aligned_type), size) == 0) - return dest; -#endif - return fallback_malloc(size); -} - -void* __calloc_with_fallback(size_t count, size_t size) { - void* ptr = std::calloc(count, size); - if (NULL != ptr) - return ptr; - // if calloc fails, fall back to emergency stash - ptr = fallback_malloc(size * count); - if (NULL != ptr) - std::memset(ptr, 0, size * count); - return ptr; -} - -void __aligned_free_with_fallback(void* ptr) { - if (is_fallback_ptr(ptr)) - fallback_free(ptr); - else { -#if defined(_WIN32) - ::_aligned_free(ptr); -#else - std::free(ptr); -#endif - } -} - -void __free_with_fallback(void* ptr) { - if (is_fallback_ptr(ptr)) - fallback_free(ptr); - else - std::free(ptr); -} - -} // namespace __cxxabiv1 diff --git a/lib/libcxxabi/src/fallback_malloc.h b/lib/libcxxabi/src/fallback_malloc.h deleted file mode 100644 index d6f471483a2..00000000000 --- a/lib/libcxxabi/src/fallback_malloc.h +++ /dev/null @@ -1,29 +0,0 @@ -//===------------------------- fallback_malloc.h --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef _FALLBACK_MALLOC_H -#define _FALLBACK_MALLOC_H - -#include "__cxxabi_config.h" -#include <cstddef> // for size_t - -namespace __cxxabiv1 { - -// Allocate some memory from _somewhere_ -_LIBCXXABI_HIDDEN void * __aligned_malloc_with_fallback(size_t size); - -// Allocate and zero-initialize memory from _somewhere_ -_LIBCXXABI_HIDDEN void * __calloc_with_fallback(size_t count, size_t size); - -_LIBCXXABI_HIDDEN void __aligned_free_with_fallback(void *ptr); -_LIBCXXABI_HIDDEN void __free_with_fallback(void *ptr); - -} // namespace __cxxabiv1 - -#endif diff --git a/lib/libcxxabi/src/include/atomic_support.h b/lib/libcxxabi/src/include/atomic_support.h deleted file mode 100644 index 96dbd2ccd16..00000000000 --- a/lib/libcxxabi/src/include/atomic_support.h +++ /dev/null @@ -1,181 +0,0 @@ -//===----------------------------------------------------------------------===//// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===//// - -// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead -// of duplicating the file in libc++abi we should require that the libc++ -// sources are available when building libc++abi. - -#ifndef ATOMIC_SUPPORT_H -#define ATOMIC_SUPPORT_H - -#include "__config" -#include "memory" // for __libcpp_relaxed_load - -#if defined(__clang__) && __has_builtin(__atomic_load_n) \ - && __has_builtin(__atomic_store_n) \ - && __has_builtin(__atomic_add_fetch) \ - && __has_builtin(__atomic_exchange_n) \ - && __has_builtin(__atomic_compare_exchange_n) \ - && defined(__ATOMIC_RELAXED) \ - && defined(__ATOMIC_CONSUME) \ - && defined(__ATOMIC_ACQUIRE) \ - && defined(__ATOMIC_RELEASE) \ - && defined(__ATOMIC_ACQ_REL) \ - && defined(__ATOMIC_SEQ_CST) -# define _LIBCXXABI_HAS_ATOMIC_BUILTINS -#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407 -# define _LIBCXXABI_HAS_ATOMIC_BUILTINS -#endif - -#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) -# if defined(_LIBCPP_WARNING) - _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported") -# else -# warning Building libc++ without __atomic builtins is unsupported -# endif -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -namespace { - -#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS) - -enum __libcpp_atomic_order { - _AO_Relaxed = __ATOMIC_RELAXED, - _AO_Consume = __ATOMIC_CONSUME, - _AO_Acquire = __ATOMIC_ACQUIRE, - _AO_Release = __ATOMIC_RELEASE, - _AO_Acq_Rel = __ATOMIC_ACQ_REL, - _AO_Seq = __ATOMIC_SEQ_CST -}; - -template <class _ValueType, class _FromType> -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int __order = _AO_Seq) -{ - __atomic_store_n(__dest, __val, __order); -} - -template <class _ValueType, class _FromType> -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - __atomic_store_n(__dest, __val, _AO_Relaxed); -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int __order = _AO_Seq) -{ - return __atomic_load_n(__val, __order); -} - -template <class _ValueType, class _AddType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int __order = _AO_Seq) -{ - return __atomic_add_fetch(__val, __a, __order); -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int __order = _AO_Seq) -{ - return __atomic_exchange_n(__target, __value, __order); -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -bool __libcpp_atomic_compare_exchange(_ValueType* __val, - _ValueType* __expected, _ValueType __after, - int __success_order = _AO_Seq, - int __fail_order = _AO_Seq) -{ - return __atomic_compare_exchange_n(__val, __expected, __after, true, - __success_order, __fail_order); -} - -#else // _LIBCPP_HAS_NO_THREADS - -enum __libcpp_atomic_order { - _AO_Relaxed, - _AO_Consume, - _AO_Acquire, - _AO_Release, - _AO_Acq_Rel, - _AO_Seq -}; - -template <class _ValueType, class _FromType> -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_atomic_store(_ValueType* __dest, _FromType __val, - int = 0) -{ - *__dest = __val; -} - -template <class _ValueType, class _FromType> -inline _LIBCPP_INLINE_VISIBILITY -void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val) -{ - *__dest = __val; -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_load(_ValueType const* __val, - int = 0) -{ - return *__val; -} - -template <class _ValueType, class _AddType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a, - int = 0) -{ - return *__val += __a; -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -_ValueType __libcpp_atomic_exchange(_ValueType* __target, - _ValueType __value, int __order = _AO_Seq) -{ - _ValueType old = *__target; - *__target = __value; - return old; -} - -template <class _ValueType> -inline _LIBCPP_INLINE_VISIBILITY -bool __libcpp_atomic_compare_exchange(_ValueType* __val, - _ValueType* __expected, _ValueType __after, - int = 0, int = 0) -{ - if (*__val == *__expected) { - *__val = __after; - return true; - } - *__expected = *__val; - return false; -} - -#endif // _LIBCPP_HAS_NO_THREADS - -} // end namespace - -_LIBCPP_END_NAMESPACE_STD - -#endif // ATOMIC_SUPPORT_H diff --git a/lib/libcxxabi/src/include/refstring.h b/lib/libcxxabi/src/include/refstring.h deleted file mode 100644 index 69f6747e125..00000000000 --- a/lib/libcxxabi/src/include/refstring.h +++ /dev/null @@ -1,132 +0,0 @@ -//===------------------------ __refstring ---------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// FIXME: This file is copied from libcxx/src/include/refstring.h. Instead of -// duplicating the file in libc++abi we should require that the libc++ sources -// are available when building libc++abi. - -#ifndef _LIBCPPABI_REFSTRING_H -#define _LIBCPPABI_REFSTRING_H - -#include <__config> -#include <stdexcept> -#include <cstddef> -#include <cstring> -#ifdef __APPLE__ -#include <dlfcn.h> -#include <mach-o/dyld.h> -#endif -#include "atomic_support.h" - -_LIBCPP_BEGIN_NAMESPACE_STD - -namespace __refstring_imp { namespace { -typedef int count_t; - -struct _Rep_base { - std::size_t len; - std::size_t cap; - count_t count; -}; - -inline _Rep_base* rep_from_data(const char *data_) noexcept { - char *data = const_cast<char *>(data_); - return reinterpret_cast<_Rep_base *>(data - sizeof(_Rep_base)); -} - -inline char * data_from_rep(_Rep_base *rep) noexcept { - char *data = reinterpret_cast<char *>(rep); - return data + sizeof(*rep); -} - -#if defined(__APPLE__) -inline -const char* compute_gcc_empty_string_storage() _NOEXCEPT -{ - void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); - if (handle == nullptr) - return nullptr; - void* sym = dlsym(handle, "_ZNSs4_Rep20_S_empty_rep_storageE"); - if (sym == nullptr) - return nullptr; - return data_from_rep(reinterpret_cast<_Rep_base *>(sym)); -} - -inline -const char* -get_gcc_empty_string_storage() _NOEXCEPT -{ - static const char* p = compute_gcc_empty_string_storage(); - return p; -} -#endif - -}} // namespace __refstring_imp - -using namespace __refstring_imp; - -inline -__libcpp_refstring::__libcpp_refstring(const char* msg) { - std::size_t len = strlen(msg); - _Rep_base* rep = static_cast<_Rep_base *>(::operator new(sizeof(*rep) + len + 1)); - rep->len = len; - rep->cap = len; - rep->count = 0; - char *data = data_from_rep(rep); - std::memcpy(data, msg, len + 1); - __imp_ = data; -} - -inline -__libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT - : __imp_(s.__imp_) -{ - if (__uses_refcount()) - __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); -} - -inline -__libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _NOEXCEPT { - bool adjust_old_count = __uses_refcount(); - struct _Rep_base *old_rep = rep_from_data(__imp_); - __imp_ = s.__imp_; - if (__uses_refcount()) - __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); - if (adjust_old_count) - { - if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) - { - ::operator delete(old_rep); - } - } - return *this; -} - -inline -__libcpp_refstring::~__libcpp_refstring() { - if (__uses_refcount()) { - _Rep_base* rep = rep_from_data(__imp_); - if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { - ::operator delete(rep); - } - } -} - -inline -bool __libcpp_refstring::__uses_refcount() const { -#ifdef __APPLE__ - return __imp_ != get_gcc_empty_string_storage(); -#else - return true; -#endif -} - -_LIBCPP_END_NAMESPACE_STD - -#endif //_LIBCPPABI_REFSTRING_H diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp deleted file mode 100644 index 30340a173cf..00000000000 --- a/lib/libcxxabi/src/private_typeinfo.cpp +++ /dev/null @@ -1,1301 +0,0 @@ -//===----------------------- private_typeinfo.cpp -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "private_typeinfo.h" - -// The flag _LIBCXX_DYNAMIC_FALLBACK is used to make dynamic_cast more -// forgiving when type_info's mistakenly have hidden visibility and thus -// multiple type_infos can exist for a single type. -// -// When _LIBCXX_DYNAMIC_FALLBACK is defined, and only in the case where -// there is a detected inconsistency in the type_info hierarchy during a -// dynamic_cast, then the equality operation will fall back to using strcmp -// on type_info names to determine type_info equality. -// -// This change happens *only* under dynamic_cast, and only when -// dynamic_cast is faced with the choice: abort, or possibly give back the -// wrong answer. If when the dynamic_cast is done with this fallback -// algorithm and an inconsistency is still detected, dynamic_cast will call -// abort with an appropriate message. -// -// The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a -// printf-like function called syslog: -// -// void syslog(int facility_priority, const char* format, ...); -// -// If you want this functionality but your platform doesn't have syslog, -// just implement it in terms of fprintf(stderr, ...). -// -// _LIBCXX_DYNAMIC_FALLBACK is currently off by default. - - -#include <string.h> - - -#ifdef _LIBCXX_DYNAMIC_FALLBACK -#include "abort_message.h" -#include <sys/syslog.h> -#endif - -// On Windows, typeids are different between DLLs and EXEs, so comparing -// type_info* will work for typeids from the same compiled file but fail -// for typeids from a DLL and an executable. Among other things, exceptions -// are not caught by handlers since can_catch() returns false. -// -// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls -// is_equal() with use_strcmp=false so the string names are not compared. - -#ifdef _WIN32 -#include <string.h> -#endif - -static inline -bool -is_equal(const std::type_info* x, const std::type_info* y, bool use_strcmp) -{ -#ifndef _WIN32 - if (!use_strcmp) - return x == y; - return strcmp(x->name(), y->name()) == 0; -#else - (void) use_strcmp; - return (x == y) || (strcmp(x->name(), y->name()) == 0); -#endif -} - -namespace __cxxabiv1 -{ - -// __shim_type_info - -__shim_type_info::~__shim_type_info() -{ -} - -void __shim_type_info::noop1() const {} -void __shim_type_info::noop2() const {} - -// __fundamental_type_info - -// This miraculously (compiler magic) emits the type_info's for: -// 1. all of the fundamental types -// 2. pointers to all of the fundamental types -// 3. pointers to all of the const fundamental types -__fundamental_type_info::~__fundamental_type_info() -{ -} - -// __array_type_info - -__array_type_info::~__array_type_info() -{ -} - -// __function_type_info - -__function_type_info::~__function_type_info() -{ -} - -// __enum_type_info - -__enum_type_info::~__enum_type_info() -{ -} - -// __class_type_info - -__class_type_info::~__class_type_info() -{ -} - -// __si_class_type_info - -__si_class_type_info::~__si_class_type_info() -{ -} - -// __vmi_class_type_info - -__vmi_class_type_info::~__vmi_class_type_info() -{ -} - -// __pbase_type_info - -__pbase_type_info::~__pbase_type_info() -{ -} - -// __pointer_type_info - -__pointer_type_info::~__pointer_type_info() -{ -} - -// __pointer_to_member_type_info - -__pointer_to_member_type_info::~__pointer_to_member_type_info() -{ -} - -// can_catch - -// A handler is a match for an exception object of type E if -// 1. The handler is of type cv T or cv T& and E and T are the same type -// (ignoring the top-level cv-qualifiers), or -// 2. the handler is of type cv T or cv T& and T is an unambiguous public -// base class of E, or -// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be -// converted to the type of the handler by either or both of -// A. a standard pointer conversion (4.10) not involving conversions to -// pointers to private or protected or ambiguous classes -// B. a qualification conversion -// 4. the handler is a pointer or pointer to member type and E is -// std::nullptr_t. - -// adjustedPtr: -// -// catch (A& a) : adjustedPtr == &a -// catch (A* a) : adjustedPtr == a -// catch (A** a) : adjustedPtr == a -// -// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object) -// catch (D2* d2) : adjustedPtr == d2 -// catch (D2*& d2) : adjustedPtr == d2 -// -// catch (...) : adjustedPtr == & of the exception -// -// If the thrown type is nullptr_t and the caught type is a pointer to -// member type, adjustedPtr points to a statically-allocated null pointer -// representation of that type. - -// Handles bullet 1 -bool -__fundamental_type_info::can_catch(const __shim_type_info* thrown_type, - void*&) const -{ - return is_equal(this, thrown_type, false); -} - -bool -__array_type_info::can_catch(const __shim_type_info*, void*&) const -{ - // We can get here if someone tries to catch an array by reference. - // However if someone tries to throw an array, it immediately gets - // converted to a pointer, which will not convert back to an array - // at the catch clause. So this can never catch anything. - return false; -} - -bool -__function_type_info::can_catch(const __shim_type_info*, void*&) const -{ - // We can get here if someone tries to catch a function by reference. - // However if someone tries to throw a function, it immediately gets - // converted to a pointer, which will not convert back to a function - // at the catch clause. So this can never catch anything. - return false; -} - -// Handles bullet 1 -bool -__enum_type_info::can_catch(const __shim_type_info* thrown_type, - void*&) const -{ - return is_equal(this, thrown_type, false); -} - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -// Handles bullets 1 and 2 -bool -__class_type_info::can_catch(const __shim_type_info* thrown_type, - void*& adjustedPtr) const -{ - // bullet 1 - if (is_equal(this, thrown_type, false)) - return true; - const __class_type_info* thrown_class_type = - dynamic_cast<const __class_type_info*>(thrown_type); - if (thrown_class_type == 0) - return false; - // bullet 2 - __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - info.number_of_dst_type = 1; - thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); - if (info.path_dst_ptr_to_static_ptr == public_path) - { - adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); - return true; - } - return false; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -void -__class_type_info::process_found_base_class(__dynamic_cast_info* info, - void* adjustedPtr, - int path_below) const -{ - if (info->dst_ptr_leading_to_static_ptr == 0) - { - // First time here - info->dst_ptr_leading_to_static_ptr = adjustedPtr; - info->path_dst_ptr_to_static_ptr = path_below; - info->number_to_static_ptr = 1; - } - else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr) - { - // We've been here before. Update path to "most public" - if (info->path_dst_ptr_to_static_ptr == not_public_path) - info->path_dst_ptr_to_static_ptr = path_below; - } - else - { - // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) - // to a static_type - info->number_to_static_ptr += 1; - info->path_dst_ptr_to_static_ptr = not_public_path; - info->search_done = true; - } -} - -void -__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, - void* adjustedPtr, - int path_below) const -{ - if (is_equal(this, info->static_type, false)) - process_found_base_class(info, adjustedPtr, path_below); -} - -void -__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, - void* adjustedPtr, - int path_below) const -{ - if (is_equal(this, info->static_type, false)) - process_found_base_class(info, adjustedPtr, path_below); - else - __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below); -} - -void -__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, - void* adjustedPtr, - int path_below) const -{ - ptrdiff_t offset_to_base = 0; - if (adjustedPtr != nullptr) - { - offset_to_base = __offset_flags >> __offset_shift; - if (__offset_flags & __virtual_mask) - { - const char* vtable = *static_cast<const char*const*>(adjustedPtr); - offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); - } - } - __base_type->has_unambiguous_public_base( - info, - static_cast<char*>(adjustedPtr) + offset_to_base, - (__offset_flags & __public_mask) ? path_below : not_public_path); -} - -void -__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, - void* adjustedPtr, - int path_below) const -{ - if (is_equal(this, info->static_type, false)) - process_found_base_class(info, adjustedPtr, path_below); - else - { - typedef const __base_class_type_info* Iter; - const Iter e = __base_info + __base_count; - Iter p = __base_info; - p->has_unambiguous_public_base(info, adjustedPtr, path_below); - if (++p < e) - { - do - { - p->has_unambiguous_public_base(info, adjustedPtr, path_below); - if (info->search_done) - break; - } while (++p < e); - } - } -} - -// Handles bullet 1 for both pointers and member pointers -bool -__pbase_type_info::can_catch(const __shim_type_info* thrown_type, - void*&) const -{ - bool use_strcmp = this->__flags & (__incomplete_class_mask | - __incomplete_mask); - if (!use_strcmp) { - const __pbase_type_info* thrown_pbase = dynamic_cast<const __pbase_type_info*>( - thrown_type); - if (!thrown_pbase) return false; - use_strcmp = thrown_pbase->__flags & (__incomplete_class_mask | - __incomplete_mask); - } - return is_equal(this, thrown_type, use_strcmp); -} - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -// Handles bullets 1, 3 and 4 -// NOTE: It might not be safe to adjust the pointer if it is not not a pointer -// type. Only adjust the pointer after we know it is safe to do so. -bool -__pointer_type_info::can_catch(const __shim_type_info* thrown_type, - void*& adjustedPtr) const -{ - // bullet 4 - if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { - adjustedPtr = nullptr; - return true; - } - - // bullet 1 - if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) { - if (adjustedPtr != NULL) - adjustedPtr = *static_cast<void**>(adjustedPtr); - return true; - } - // bullet 3 - const __pointer_type_info* thrown_pointer_type = - dynamic_cast<const __pointer_type_info*>(thrown_type); - if (thrown_pointer_type == 0) - return false; - // Do the dereference adjustment - if (adjustedPtr != NULL) - adjustedPtr = *static_cast<void**>(adjustedPtr); - // bullet 3B and 3C - if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) - return false; - if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) - return false; - if (is_equal(__pointee, thrown_pointer_type->__pointee, false)) - return true; - // bullet 3A - if (is_equal(__pointee, &typeid(void), false)) { - // pointers to functions cannot be converted to void*. - // pointers to member functions are not handled here. - const __function_type_info* thrown_function = - dynamic_cast<const __function_type_info*>(thrown_pointer_type->__pointee); - return (thrown_function == nullptr); - } - // Handle pointer to pointer - const __pointer_type_info* nested_pointer_type = - dynamic_cast<const __pointer_type_info*>(__pointee); - if (nested_pointer_type) { - if (~__flags & __const_mask) return false; - return nested_pointer_type->can_catch_nested(thrown_pointer_type->__pointee); - } - - // Handle pointer to pointer to member - const __pointer_to_member_type_info* member_ptr_type = - dynamic_cast<const __pointer_to_member_type_info*>(__pointee); - if (member_ptr_type) { - if (~__flags & __const_mask) return false; - return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee); - } - - // Handle pointer to class type - const __class_type_info* catch_class_type = - dynamic_cast<const __class_type_info*>(__pointee); - if (catch_class_type == 0) - return false; - const __class_type_info* thrown_class_type = - dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); - if (thrown_class_type == 0) - return false; - __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - info.number_of_dst_type = 1; - thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); - if (info.path_dst_ptr_to_static_ptr == public_path) - { - if (adjustedPtr != NULL) - adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); - return true; - } - return false; -} - -bool __pointer_type_info::can_catch_nested( - const __shim_type_info* thrown_type) const -{ - const __pointer_type_info* thrown_pointer_type = - dynamic_cast<const __pointer_type_info*>(thrown_type); - if (thrown_pointer_type == 0) - return false; - // bullet 3B - if (thrown_pointer_type->__flags & ~__flags) - return false; - if (is_equal(__pointee, thrown_pointer_type->__pointee, false)) - return true; - // If the pointed to types differ then the catch type must be const - // qualified. - if (~__flags & __const_mask) - return false; - - // Handle pointer to pointer - const __pointer_type_info* nested_pointer_type = - dynamic_cast<const __pointer_type_info*>(__pointee); - if (nested_pointer_type) { - return nested_pointer_type->can_catch_nested( - thrown_pointer_type->__pointee); - } - - // Handle pointer to pointer to member - const __pointer_to_member_type_info* member_ptr_type = - dynamic_cast<const __pointer_to_member_type_info*>(__pointee); - if (member_ptr_type) { - return member_ptr_type->can_catch_nested(thrown_pointer_type->__pointee); - } - - return false; -} - -bool __pointer_to_member_type_info::can_catch( - const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // bullet 4 - if (is_equal(thrown_type, &typeid(std::nullptr_t), false)) { - // We assume that the pointer to member representation is the same for - // all pointers to data members and for all pointers to member functions. - struct X {}; - if (dynamic_cast<const __function_type_info*>(__pointee)) { - static int (X::*const null_ptr_rep)() = nullptr; - adjustedPtr = const_cast<int (X::**)()>(&null_ptr_rep); - } else { - static int X::*const null_ptr_rep = nullptr; - adjustedPtr = const_cast<int X::**>(&null_ptr_rep); - } - return true; - } - - // bullet 1 - if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) - return true; - - const __pointer_to_member_type_info* thrown_pointer_type = - dynamic_cast<const __pointer_to_member_type_info*>(thrown_type); - if (thrown_pointer_type == 0) - return false; - if (thrown_pointer_type->__flags & ~__flags & __no_remove_flags_mask) - return false; - if (__flags & ~thrown_pointer_type->__flags & __no_add_flags_mask) - return false; - if (!is_equal(__pointee, thrown_pointer_type->__pointee, false)) - return false; - if (is_equal(__context, thrown_pointer_type->__context, false)) - return true; - - // [except.handle] does not allow the pointer-to-member conversions mentioned - // in [mem.conv] to take place. For this reason we don't check Derived->Base - // for Derived->Base conversions. - - return false; -} - -bool __pointer_to_member_type_info::can_catch_nested( - const __shim_type_info* thrown_type) const -{ - const __pointer_to_member_type_info* thrown_member_ptr_type = - dynamic_cast<const __pointer_to_member_type_info*>(thrown_type); - if (thrown_member_ptr_type == 0) - return false; - if (~__flags & thrown_member_ptr_type->__flags) - return false; - if (!is_equal(__pointee, thrown_member_ptr_type->__pointee, false)) - return false; - if (!is_equal(__context, thrown_member_ptr_type->__context, false)) - return false; - return true; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#endif - -// __dynamic_cast - -// static_ptr: pointer to an object of type static_type; nonnull, and since the -// object is polymorphic, *(void**)static_ptr is a virtual table pointer. -// static_ptr is &v in the expression dynamic_cast<T>(v). -// static_type: static type of the object pointed to by static_ptr. -// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)"). -// src2dst_offset: a static hint about the location of the -// source subobject with respect to the complete object; -// special negative values are: -// -1: no hint -// -2: static_type is not a public base of dst_type -// -3: static_type is a multiple public base type but never a -// virtual base type -// otherwise, the static_type type is a unique public nonvirtual -// base type of dst_type at offset src2dst_offset from the -// origin of dst_type. -// -// (dynamic_ptr, dynamic_type) are the run time type of the complete object -// referred to by static_ptr and a pointer to it. These can be found from -// static_ptr for polymorphic types. -// static_type is guaranteed to be a polymorphic type. -// -// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each -// node of the tree represents a base class/object of its parent (or parents) below. -// Each node is uniquely represented by a pointer to the object, and a pointer -// to a type_info - its type. Different nodes may have the same pointer and -// different nodes may have the same type. But only one node has a specific -// (pointer-value, type) pair. In C++ two objects of the same type can not -// share the same address. -// -// There are two flavors of nodes which have the type dst_type: -// 1. Those that are derived from (below) (static_ptr, static_type). -// 2. Those that are not derived from (below) (static_ptr, static_type). -// -// Invariants of the DAG: -// -// There is at least one path from the root (dynamic_ptr, dynamic_type) to -// the node (static_ptr, static_type). This path may or may not be public. -// There may be more than one such path (some public some not). Such a path may -// or may not go through a node having type dst_type. -// -// No node of type T appears above a node of the same type. That means that -// there is only one node with dynamic_type. And if dynamic_type == dst_type, -// then there is only one dst_type in the DAG. -// -// No node of type dst_type appears above a node of type static_type. Such -// DAG's are possible in C++, but the compiler computes those dynamic_casts at -// compile time, and only calls __dynamic_cast when dst_type lies below -// static_type in the DAG. -// -// dst_type != static_type: The compiler computes the dynamic_cast in this case too. -// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too. -// -// Returns: -// -// If there is exactly one dst_type of flavor 1, and -// If there is a public path from that dst_type to (static_ptr, static_type), or -// If there are 0 dst_types of flavor 2, and there is a public path from -// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public -// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return -// a pointer to that dst_type. -// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and -// if there is a public path from (dynamic_ptr, dynamic_type) to -// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type) -// to the one dst_type, then return a pointer to that one dst_type. -// Else return nullptr. -// -// If dynamic_type == dst_type, then the above algorithm collapses to the -// following cheaper algorithm: -// -// If there is a public path from (dynamic_ptr, dynamic_type) to -// (static_ptr, static_type), then return dynamic_ptr. -// Else return nullptr. - -extern "C" _LIBCXXABI_FUNC_VIS void * -__dynamic_cast(const void *static_ptr, const __class_type_info *static_type, - const __class_type_info *dst_type, - std::ptrdiff_t src2dst_offset) { - // Possible future optimization: Take advantage of src2dst_offset - // Currently clang always sets src2dst_offset to -1 (no hint). - - // Get (dynamic_ptr, dynamic_type) from static_ptr - void **vtable = *static_cast<void ** const *>(static_ptr); - ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]); - const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived; - const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]); - - // Initialize answer to nullptr. This will be changed from the search - // results if a non-null answer is found. Regardless, this is what will - // be returned. - const void* dst_ptr = 0; - // Initialize info struct for this search. - __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - - // Find out if we can use a giant short cut in the search - if (is_equal(dynamic_type, dst_type, false)) - { - // Using giant short cut. Add that information to info. - info.number_of_dst_type = 1; - // Do the search - dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); -#ifdef _LIBCXX_DYNAMIC_FALLBACK - // The following if should always be false because we should definitely - // find (static_ptr, static_type), either on a public or private path - if (info.path_dst_ptr_to_static_ptr == unknown) - { - // We get here only if there is some kind of visibility problem - // in client code. - syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " - "should have public visibility. At least one of them is hidden. %s" - ", %s.\n", static_type->name(), dynamic_type->name()); - // Redo the search comparing type_info's using strcmp - info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; - info.number_of_dst_type = 1; - dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); - } -#endif // _LIBCXX_DYNAMIC_FALLBACK - // Query the search. - if (info.path_dst_ptr_to_static_ptr == public_path) - dst_ptr = dynamic_ptr; - } - else - { - // Not using giant short cut. Do the search - dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); - #ifdef _LIBCXX_DYNAMIC_FALLBACK - // The following if should always be false because we should definitely - // find (static_ptr, static_type), either on a public or private path - if (info.path_dst_ptr_to_static_ptr == unknown && - info.path_dynamic_ptr_to_static_ptr == unknown) - { - syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " - "has hidden visibility or is defined in more than one translation " - "unit. They should all have public visibility. " - "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), - dst_type->name()); - // Redo the search comparing type_info's using strcmp - info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; - dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); - } -#endif // _LIBCXX_DYNAMIC_FALLBACK - // Query the search. - switch (info.number_to_static_ptr) - { - case 0: - if (info.number_to_dst_ptr == 1 && - info.path_dynamic_ptr_to_static_ptr == public_path && - info.path_dynamic_ptr_to_dst_ptr == public_path) - dst_ptr = info.dst_ptr_not_leading_to_static_ptr; - break; - case 1: - if (info.path_dst_ptr_to_static_ptr == public_path || - ( - info.number_to_dst_ptr == 0 && - info.path_dynamic_ptr_to_static_ptr == public_path && - info.path_dynamic_ptr_to_dst_ptr == public_path - ) - ) - dst_ptr = info.dst_ptr_leading_to_static_ptr; - break; - } - } - return const_cast<void*>(dst_ptr); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// Call this function when you hit a static_type which is a base (above) a dst_type. -// Let caller know you hit a static_type. But only start recording details if -// this is (static_ptr, static_type) -- the node we are casting from. -// If this is (static_ptr, static_type) -// Record the path (public or not) from the dst_type to here. There may be -// multiple paths from the same dst_type to here, record the "most public" one. -// Record the dst_ptr as pointing to (static_ptr, static_type). -// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type), -// then mark this dyanmic_cast as ambiguous and stop the search. -void -__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info, - const void* dst_ptr, - const void* current_ptr, - int path_below) const -{ - // Record that we found a static_type - info->found_any_static_type = true; - if (current_ptr == info->static_ptr) - { - // Record that we found (static_ptr, static_type) - info->found_our_static_ptr = true; - if (info->dst_ptr_leading_to_static_ptr == 0) - { - // First time here - info->dst_ptr_leading_to_static_ptr = dst_ptr; - info->path_dst_ptr_to_static_ptr = path_below; - info->number_to_static_ptr = 1; - // If there is only one dst_type in the entire tree and the path from - // there to here is public then we are done! - if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) - info->search_done = true; - } - else if (info->dst_ptr_leading_to_static_ptr == dst_ptr) - { - // We've been here before. Update path to "most public" - if (info->path_dst_ptr_to_static_ptr == not_public_path) - info->path_dst_ptr_to_static_ptr = path_below; - // If there is only one dst_type in the entire tree and the path from - // there to here is public then we are done! - if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) - info->search_done = true; - } - else - { - // We've detected an ambiguous cast from (static_ptr, static_type) - // to a dst_type - info->number_to_static_ptr += 1; - info->search_done = true; - } - } -} - -// Call this function when you hit a static_type which is not a base (above) a dst_type. -// If this is (static_ptr, static_type) -// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be -// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one. -void -__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info, - const void* current_ptr, - int path_below) const -{ - if (current_ptr == info->static_ptr) - { - // Record the most public path from (dynamic_ptr, dynamic_type) to - // (static_ptr, static_type) - if (info->path_dynamic_ptr_to_static_ptr != public_path) - info->path_dynamic_ptr_to_static_ptr = path_below; - } -} - -// Call this function when searching below a dst_type node. This function searches -// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes. -// If it finds a static_type node, there is no need to further search base classes -// above. -// If it finds a dst_type node it should search base classes using search_above_dst -// to find out if this dst_type points to (static_ptr, static_type) or not. -// Either way, the dst_type is recorded as one of two "flavors": one that does -// or does not point to (static_ptr, static_type). -// If this is neither a static_type nor a dst_type node, continue searching -// base classes above. -// All the hoopla surrounding the search code is doing nothing but looking for -// excuses to stop the search prematurely (break out of the for-loop). That is, -// the algorithm below is simply an optimization of this: -// void -// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, -// const void* current_ptr, -// int path_below) const -// { -// typedef const __base_class_type_info* Iter; -// if (this == info->static_type) -// process_static_type_below_dst(info, current_ptr, path_below); -// else if (this == info->dst_type) -// { -// // Record the most public access path that got us here -// if (info->path_dynamic_ptr_to_dst_ptr != public_path) -// info->path_dynamic_ptr_to_dst_ptr = path_below; -// bool does_dst_type_point_to_our_static_type = false; -// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p) -// { -// p->search_above_dst(info, current_ptr, current_ptr, public_path); -// if (info->found_our_static_ptr) -// does_dst_type_point_to_our_static_type = true; -// // break out early here if you can detect it doesn't matter if you do -// } -// if (!does_dst_type_point_to_our_static_type) -// { -// // We found a dst_type that doesn't point to (static_ptr, static_type) -// // So record the address of this dst_ptr and increment the -// // count of the number of such dst_types found in the tree. -// info->dst_ptr_not_leading_to_static_ptr = current_ptr; -// info->number_to_dst_ptr += 1; -// } -// } -// else -// { -// // This is not a static_type and not a dst_type. -// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) -// { -// p->search_below_dst(info, current_ptr, public_path); -// // break out early here if you can detect it doesn't matter if you do -// } -// } -// } -void -__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - typedef const __base_class_type_info* Iter; - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_below_dst(info, current_ptr, path_below); - else if (is_equal(this, info->dst_type, use_strcmp)) - { - // We've been here before if we've recorded current_ptr in one of these - // two places: - if (current_ptr == info->dst_ptr_leading_to_static_ptr || - current_ptr == info->dst_ptr_not_leading_to_static_ptr) - { - // We've seen this node before, and therefore have already searched - // its base classes above. - // Update path to here that is "most public". - if (path_below == public_path) - info->path_dynamic_ptr_to_dst_ptr = public_path; - } - else // We have haven't been here before - { - // Record the access path that got us here - // If there is more than one dst_type this path doesn't matter. - info->path_dynamic_ptr_to_dst_ptr = path_below; - bool does_dst_type_point_to_our_static_type = false; - // Only search above here if dst_type derives from static_type, or - // if it is unknown if dst_type derives from static_type. - if (info->is_dst_type_derived_from_static_type != no) - { - // Set up flags to record results from all base classes - bool is_dst_type_derived_from_static_type = false; - - // We've found a dst_type with a potentially public path to here. - // We have to assume the path is public because it may become - // public later (if we get back to here with a public path). - // We can stop looking above if: - // 1. We've found a public path to (static_ptr, static_type). - // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. - // This is detected at the (static_ptr, static_type). - // 3. We can prove that there is no public path to (static_ptr, static_type) - // above here. - const Iter e = __base_info + __base_count; - for (Iter p = __base_info; p < e; ++p) - { - // Zero out found flags - info->found_our_static_ptr = false; - info->found_any_static_type = false; - p->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp); - if (info->search_done) - break; - if (info->found_any_static_type) - { - is_dst_type_derived_from_static_type = true; - if (info->found_our_static_ptr) - { - does_dst_type_point_to_our_static_type = true; - // If we found what we're looking for, stop looking above. - if (info->path_dst_ptr_to_static_ptr == public_path) - break; - // We found a private path to (static_ptr, static_type) - // If there is no diamond then there is only one path - // to (static_ptr, static_type) and we just found it. - if (!(__flags & __diamond_shaped_mask)) - break; - } - else - { - // If we found a static_type that isn't the one we're looking - // for, and if there are no repeated types above here, - // then stop looking. - if (!(__flags & __non_diamond_repeat_mask)) - break; - } - } - } - // If we found no static_type,s then dst_type doesn't derive - // from static_type, else it does. Record this result so that - // next time we hit a dst_type we will know not to search above - // it if it doesn't derive from static_type. - if (is_dst_type_derived_from_static_type) - info->is_dst_type_derived_from_static_type = yes; - else - info->is_dst_type_derived_from_static_type = no; - } - if (!does_dst_type_point_to_our_static_type) - { - // We found a dst_type that doesn't point to (static_ptr, static_type) - // So record the address of this dst_ptr and increment the - // count of the number of such dst_types found in the tree. - info->dst_ptr_not_leading_to_static_ptr = current_ptr; - info->number_to_dst_ptr += 1; - // If there exists another dst with a private path to - // (static_ptr, static_type), then the cast from - // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous, - // so stop search. - if (info->number_to_static_ptr == 1 && - info->path_dst_ptr_to_static_ptr == not_public_path) - info->search_done = true; - } - } - } - else - { - // This is not a static_type and not a dst_type. - const Iter e = __base_info + __base_count; - Iter p = __base_info; - p->search_below_dst(info, current_ptr, path_below, use_strcmp); - if (++p < e) - { - if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1) - { - // If there are multiple paths to a base above from here, or if - // a dst_type pointing to (static_ptr, static_type) has been found, - // then there is no way to break out of this loop early unless - // something below detects the search is done. - do - { - if (info->search_done) - break; - p->search_below_dst(info, current_ptr, path_below, use_strcmp); - } while (++p < e); - } - else if (__flags & __non_diamond_repeat_mask) - { - // There are not multiple paths to any base class from here and a - // dst_type pointing to (static_ptr, static_type) has not yet been - // found. - do - { - if (info->search_done) - break; - // If we just found a dst_type with a public path to (static_ptr, static_type), - // then the only reason to continue the search is to make sure - // no other dst_type points to (static_ptr, static_type). - // If !diamond, then we don't need to search here. - if (info->number_to_static_ptr == 1 && - info->path_dst_ptr_to_static_ptr == public_path) - break; - p->search_below_dst(info, current_ptr, path_below, use_strcmp); - } while (++p < e); - } - else - { - // There are no repeated types above this node. - // There are no nodes with multiple parents above this node. - // no dst_type has been found to (static_ptr, static_type) - do - { - if (info->search_done) - break; - // If we just found a dst_type with a public path to (static_ptr, static_type), - // then the only reason to continue the search is to make sure sure - // no other dst_type points to (static_ptr, static_type). - // If !diamond, then we don't need to search here. - // if we just found a dst_type with a private path to (static_ptr, static_type), - // then we're only looking for a public path to (static_ptr, static_type) - // and to check for other dst_types. - // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type) - // and not a dst_type under here. - if (info->number_to_static_ptr == 1) - break; - p->search_below_dst(info, current_ptr, path_below, use_strcmp); - } while (++p < e); - } - } - } -} - -// This is the same algorithm as __vmi_class_type_info::search_below_dst but -// simplified to the case that there is only a single base class. -void -__si_class_type_info::search_below_dst(__dynamic_cast_info* info, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_below_dst(info, current_ptr, path_below); - else if (is_equal(this, info->dst_type, use_strcmp)) - { - // We've been here before if we've recorded current_ptr in one of these - // two places: - if (current_ptr == info->dst_ptr_leading_to_static_ptr || - current_ptr == info->dst_ptr_not_leading_to_static_ptr) - { - // We've seen this node before, and therefore have already searched - // its base classes above. - // Update path to here that is "most public". - if (path_below == public_path) - info->path_dynamic_ptr_to_dst_ptr = public_path; - } - else // We have haven't been here before - { - // Record the access path that got us here - // If there is more than one dst_type this path doesn't matter. - info->path_dynamic_ptr_to_dst_ptr = path_below; - bool does_dst_type_point_to_our_static_type = false; - // Only search above here if dst_type derives from static_type, or - // if it is unknown if dst_type derives from static_type. - if (info->is_dst_type_derived_from_static_type != no) - { - // Set up flags to record results from all base classes - bool is_dst_type_derived_from_static_type = false; - // Zero out found flags - info->found_our_static_ptr = false; - info->found_any_static_type = false; - __base_type->search_above_dst(info, current_ptr, current_ptr, public_path, use_strcmp); - if (info->found_any_static_type) - { - is_dst_type_derived_from_static_type = true; - if (info->found_our_static_ptr) - does_dst_type_point_to_our_static_type = true; - } - // If we found no static_type,s then dst_type doesn't derive - // from static_type, else it does. Record this result so that - // next time we hit a dst_type we will know not to search above - // it if it doesn't derive from static_type. - if (is_dst_type_derived_from_static_type) - info->is_dst_type_derived_from_static_type = yes; - else - info->is_dst_type_derived_from_static_type = no; - } - if (!does_dst_type_point_to_our_static_type) - { - // We found a dst_type that doesn't point to (static_ptr, static_type) - // So record the address of this dst_ptr and increment the - // count of the number of such dst_types found in the tree. - info->dst_ptr_not_leading_to_static_ptr = current_ptr; - info->number_to_dst_ptr += 1; - // If there exists another dst with a private path to - // (static_ptr, static_type), then the cast from - // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. - if (info->number_to_static_ptr == 1 && - info->path_dst_ptr_to_static_ptr == not_public_path) - info->search_done = true; - } - } - } - else - { - // This is not a static_type and not a dst_type - __base_type->search_below_dst(info, current_ptr, path_below, use_strcmp); - } -} - -// This is the same algorithm as __vmi_class_type_info::search_below_dst but -// simplified to the case that there is no base class. -void -__class_type_info::search_below_dst(__dynamic_cast_info* info, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_below_dst(info, current_ptr, path_below); - else if (is_equal(this, info->dst_type, use_strcmp)) - { - // We've been here before if we've recorded current_ptr in one of these - // two places: - if (current_ptr == info->dst_ptr_leading_to_static_ptr || - current_ptr == info->dst_ptr_not_leading_to_static_ptr) - { - // We've seen this node before, and therefore have already searched - // its base classes above. - // Update path to here that is "most public". - if (path_below == public_path) - info->path_dynamic_ptr_to_dst_ptr = public_path; - } - else // We have haven't been here before - { - // Record the access path that got us here - // If there is more than one dst_type this path doesn't matter. - info->path_dynamic_ptr_to_dst_ptr = path_below; - // We found a dst_type that doesn't point to (static_ptr, static_type) - // So record the address of this dst_ptr and increment the - // count of the number of such dst_types found in the tree. - info->dst_ptr_not_leading_to_static_ptr = current_ptr; - info->number_to_dst_ptr += 1; - // If there exists another dst with a private path to - // (static_ptr, static_type), then the cast from - // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. - if (info->number_to_static_ptr == 1 && - info->path_dst_ptr_to_static_ptr == not_public_path) - info->search_done = true; - // We found that dst_type does not derive from static_type - info->is_dst_type_derived_from_static_type = no; - } - } -} - -// Call this function when searching above a dst_type node. This function searches -// for a public path to (static_ptr, static_type). -// This function is guaranteed not to find a node of type dst_type. -// Theoretically this is a very simple function which just stops if it finds a -// static_type node: All the hoopla surrounding the search code is doing -// nothing but looking for excuses to stop the search prematurely (break out of -// the for-loop). That is, the algorithm below is simply an optimization of this: -// void -// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, -// const void* dst_ptr, -// const void* current_ptr, -// int path_below) const -// { -// if (this == info->static_type) -// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); -// else -// { -// typedef const __base_class_type_info* Iter; -// // This is not a static_type and not a dst_type -// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) -// { -// p->search_above_dst(info, dst_ptr, current_ptr, public_path); -// // break out early here if you can detect it doesn't matter if you do -// } -// } -// } -void -__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, - const void* dst_ptr, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); - else - { - typedef const __base_class_type_info* Iter; - // This is not a static_type and not a dst_type - // Save flags so they can be restored when returning to nodes below. - bool found_our_static_ptr = info->found_our_static_ptr; - bool found_any_static_type = info->found_any_static_type; - // We've found a dst_type below with a path to here. If the path - // to here is not public, there may be another path to here that - // is public. So we have to assume that the path to here is public. - // We can stop looking above if: - // 1. We've found a public path to (static_ptr, static_type). - // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. - // This is detected at the (static_ptr, static_type). - // 3. We can prove that there is no public path to (static_ptr, static_type) - // above here. - const Iter e = __base_info + __base_count; - Iter p = __base_info; - // Zero out found flags - info->found_our_static_ptr = false; - info->found_any_static_type = false; - p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); - found_our_static_ptr |= info->found_our_static_ptr; - found_any_static_type |= info->found_any_static_type; - if (++p < e) - { - do - { - if (info->search_done) - break; - if (info->found_our_static_ptr) - { - // If we found what we're looking for, stop looking above. - if (info->path_dst_ptr_to_static_ptr == public_path) - break; - // We found a private path to (static_ptr, static_type) - // If there is no diamond then there is only one path - // to (static_ptr, static_type) from here and we just found it. - if (!(__flags & __diamond_shaped_mask)) - break; - } - else if (info->found_any_static_type) - { - // If we found a static_type that isn't the one we're looking - // for, and if there are no repeated types above here, - // then stop looking. - if (!(__flags & __non_diamond_repeat_mask)) - break; - } - // Zero out found flags - info->found_our_static_ptr = false; - info->found_any_static_type = false; - p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); - found_our_static_ptr |= info->found_our_static_ptr; - found_any_static_type |= info->found_any_static_type; - } while (++p < e); - } - // Restore flags - info->found_our_static_ptr = found_our_static_ptr; - info->found_any_static_type = found_any_static_type; - } -} - -// This is the same algorithm as __vmi_class_type_info::search_above_dst but -// simplified to the case that there is only a single base class. -void -__si_class_type_info::search_above_dst(__dynamic_cast_info* info, - const void* dst_ptr, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); - else - __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp); -} - -// This is the same algorithm as __vmi_class_type_info::search_above_dst but -// simplified to the case that there is no base class. -void -__class_type_info::search_above_dst(__dynamic_cast_info* info, - const void* dst_ptr, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - if (is_equal(this, info->static_type, use_strcmp)) - process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); -} - -// The search functions for __base_class_type_info are simply convenience -// functions for adjusting the current_ptr and path_below as the search is -// passed up to the base class node. - -void -__base_class_type_info::search_above_dst(__dynamic_cast_info* info, - const void* dst_ptr, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; - if (__offset_flags & __virtual_mask) - { - const char* vtable = *static_cast<const char*const*>(current_ptr); - offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); - } - __base_type->search_above_dst(info, dst_ptr, - static_cast<const char*>(current_ptr) + offset_to_base, - (__offset_flags & __public_mask) ? - path_below : - not_public_path, - use_strcmp); -} - -void -__base_class_type_info::search_below_dst(__dynamic_cast_info* info, - const void* current_ptr, - int path_below, - bool use_strcmp) const -{ - ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; - if (__offset_flags & __virtual_mask) - { - const char* vtable = *static_cast<const char*const*>(current_ptr); - offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); - } - __base_type->search_below_dst(info, - static_cast<const char*>(current_ptr) + offset_to_base, - (__offset_flags & __public_mask) ? - path_below : - not_public_path, - use_strcmp); -} - -} // __cxxabiv1 diff --git a/lib/libcxxabi/src/private_typeinfo.h b/lib/libcxxabi/src/private_typeinfo.h deleted file mode 100644 index 3922ae6ef56..00000000000 --- a/lib/libcxxabi/src/private_typeinfo.h +++ /dev/null @@ -1,252 +0,0 @@ -//===------------------------ private_typeinfo.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 __PRIVATE_TYPEINFO_H_ -#define __PRIVATE_TYPEINFO_H_ - -#include "__cxxabi_config.h" - -#include <typeinfo> -#include <cstddef> - -namespace __cxxabiv1 { - -class _LIBCXXABI_TYPE_VIS __shim_type_info : public std::type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__shim_type_info(); - - _LIBCXXABI_HIDDEN virtual void noop1() const; - _LIBCXXABI_HIDDEN virtual void noop2() const; - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *thrown_type, - void *&adjustedPtr) const = 0; -}; - -class _LIBCXXABI_TYPE_VIS __fundamental_type_info : public __shim_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__fundamental_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; -}; - -class _LIBCXXABI_TYPE_VIS __array_type_info : public __shim_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__array_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; -}; - -class _LIBCXXABI_TYPE_VIS __function_type_info : public __shim_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__function_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; -}; - -class _LIBCXXABI_TYPE_VIS __enum_type_info : public __shim_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__enum_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; -}; - -enum -{ - unknown = 0, - public_path, - not_public_path, - yes, - no -}; - -class _LIBCXXABI_TYPE_VIS __class_type_info; - -struct _LIBCXXABI_HIDDEN __dynamic_cast_info -{ -// const data supplied to the search: - - const __class_type_info* dst_type; - const void* static_ptr; - const __class_type_info* static_type; - std::ptrdiff_t src2dst_offset; - -// Data that represents the answer: - - // pointer to a dst_type which has (static_ptr, static_type) above it - const void* dst_ptr_leading_to_static_ptr; - // pointer to a dst_type which does not have (static_ptr, static_type) above it - const void* dst_ptr_not_leading_to_static_ptr; - - // The following three paths are either unknown, public_path or not_public_path. - // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type) - int path_dst_ptr_to_static_ptr; - // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type) - // when there is no dst_type along the path - int path_dynamic_ptr_to_static_ptr; - // access of path from (dynamic_ptr, dynamic_type) to dst_type - // (not used if there is a (static_ptr, static_type) above a dst_type). - int path_dynamic_ptr_to_dst_ptr; - - // Number of dst_types below (static_ptr, static_type) - int number_to_static_ptr; - // Number of dst_types not below (static_ptr, static_type) - int number_to_dst_ptr; - -// Data that helps stop the search before the entire tree is searched: - - // is_dst_type_derived_from_static_type is either unknown, yes or no. - int is_dst_type_derived_from_static_type; - // Number of dst_type in tree. If 0, then that means unknown. - int number_of_dst_type; - // communicates to a dst_type node that (static_ptr, static_type) was found - // above it. - bool found_our_static_ptr; - // communicates to a dst_type node that a static_type was found - // above it, but it wasn't (static_ptr, static_type) - bool found_any_static_type; - // Set whenever a search can be stopped - bool search_done; -}; - -// Has no base class -class _LIBCXXABI_TYPE_VIS __class_type_info : public __shim_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__class_type_info(); - - _LIBCXXABI_HIDDEN void process_static_type_above_dst(__dynamic_cast_info *, - const void *, - const void *, int) const; - _LIBCXXABI_HIDDEN void process_static_type_below_dst(__dynamic_cast_info *, - const void *, int) const; - _LIBCXXABI_HIDDEN void process_found_base_class(__dynamic_cast_info *, void *, - int) const; - _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *, - const void *, const void *, - int, bool) const; - _LIBCXXABI_HIDDEN virtual void - search_below_dst(__dynamic_cast_info *, const void *, int, bool) const; - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; - _LIBCXXABI_HIDDEN virtual void - has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const; -}; - -// Has one non-virtual public base class at offset zero -class _LIBCXXABI_TYPE_VIS __si_class_type_info : public __class_type_info { -public: - const __class_type_info *__base_type; - - _LIBCXXABI_HIDDEN virtual ~__si_class_type_info(); - - _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *, - const void *, const void *, - int, bool) const; - _LIBCXXABI_HIDDEN virtual void - search_below_dst(__dynamic_cast_info *, const void *, int, bool) const; - _LIBCXXABI_HIDDEN virtual void - has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const; -}; - -struct _LIBCXXABI_HIDDEN __base_class_type_info -{ -public: - const __class_type_info* __base_type; - long __offset_flags; - - enum __offset_flags_masks - { - __virtual_mask = 0x1, - __public_mask = 0x2, // base is public - __offset_shift = 8 - }; - - void search_above_dst(__dynamic_cast_info*, const void*, const void*, int, bool) const; - void search_below_dst(__dynamic_cast_info*, const void*, int, bool) const; - void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; -}; - -// Has one or more base classes -class _LIBCXXABI_TYPE_VIS __vmi_class_type_info : public __class_type_info { -public: - unsigned int __flags; - unsigned int __base_count; - __base_class_type_info __base_info[1]; - - enum __flags_masks { - __non_diamond_repeat_mask = 0x1, // has two or more distinct base class - // objects of the same type - __diamond_shaped_mask = 0x2 // has base class object with two or - // more derived objects - }; - - _LIBCXXABI_HIDDEN virtual ~__vmi_class_type_info(); - - _LIBCXXABI_HIDDEN virtual void search_above_dst(__dynamic_cast_info *, - const void *, const void *, - int, bool) const; - _LIBCXXABI_HIDDEN virtual void - search_below_dst(__dynamic_cast_info *, const void *, int, bool) const; - _LIBCXXABI_HIDDEN virtual void - has_unambiguous_public_base(__dynamic_cast_info *, void *, int) const; -}; - -class _LIBCXXABI_TYPE_VIS __pbase_type_info : public __shim_type_info { -public: - unsigned int __flags; - const __shim_type_info *__pointee; - - enum __masks { - __const_mask = 0x1, - __volatile_mask = 0x2, - __restrict_mask = 0x4, - __incomplete_mask = 0x8, - __incomplete_class_mask = 0x10, - __transaction_safe_mask = 0x20, - // This implements the following proposal from cxx-abi-dev (not yet part of - // the ABI document): - // - // http://sourcerytools.com/pipermail/cxx-abi-dev/2016-October/002986.html - // - // This is necessary for support of http://wg21.link/p0012, which permits - // throwing noexcept function and member function pointers and catching - // them as non-noexcept pointers. - __noexcept_mask = 0x40, - - // Flags that cannot be removed by a standard conversion. - __no_remove_flags_mask = __const_mask | __volatile_mask | __restrict_mask, - // Flags that cannot be added by a standard conversion. - __no_add_flags_mask = __transaction_safe_mask | __noexcept_mask - }; - - _LIBCXXABI_HIDDEN virtual ~__pbase_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; -}; - -class _LIBCXXABI_TYPE_VIS __pointer_type_info : public __pbase_type_info { -public: - _LIBCXXABI_HIDDEN virtual ~__pointer_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; - _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const; -}; - -class _LIBCXXABI_TYPE_VIS __pointer_to_member_type_info - : public __pbase_type_info { -public: - const __class_type_info *__context; - - _LIBCXXABI_HIDDEN virtual ~__pointer_to_member_type_info(); - _LIBCXXABI_HIDDEN virtual bool can_catch(const __shim_type_info *, - void *&) const; - _LIBCXXABI_HIDDEN bool can_catch_nested(const __shim_type_info *) const; -}; - -} // __cxxabiv1 - -#endif // __PRIVATE_TYPEINFO_H_ diff --git a/lib/libcxxabi/src/stdlib_exception.cpp b/lib/libcxxabi/src/stdlib_exception.cpp deleted file mode 100644 index 0308e169a83..00000000000 --- a/lib/libcxxabi/src/stdlib_exception.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===---------------------------- exception.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#define _LIBCPP_BUILDING_LIBRARY -#include <new> -#include <exception> - -namespace std -{ - -// exception - -exception::~exception() _NOEXCEPT -{ -} - -const char* exception::what() const _NOEXCEPT -{ - return "std::exception"; -} - -// bad_exception - -bad_exception::~bad_exception() _NOEXCEPT -{ -} - -const char* bad_exception::what() const _NOEXCEPT -{ - return "std::bad_exception"; -} - - -// bad_alloc - -bad_alloc::bad_alloc() _NOEXCEPT -{ -} - -bad_alloc::~bad_alloc() _NOEXCEPT -{ -} - -const char* -bad_alloc::what() const _NOEXCEPT -{ - return "std::bad_alloc"; -} - -// bad_array_new_length - -bad_array_new_length::bad_array_new_length() _NOEXCEPT -{ -} - -bad_array_new_length::~bad_array_new_length() _NOEXCEPT -{ -} - -const char* -bad_array_new_length::what() const _NOEXCEPT -{ - return "bad_array_new_length"; -} - -} // std diff --git a/lib/libcxxabi/src/stdlib_new_delete.cpp b/lib/libcxxabi/src/stdlib_new_delete.cpp deleted file mode 100644 index bbd90a5b26d..00000000000 --- a/lib/libcxxabi/src/stdlib_new_delete.cpp +++ /dev/null @@ -1,263 +0,0 @@ -//===--------------------- stdlib_new_delete.cpp --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -// -// This file implements the new and delete operators. -//===----------------------------------------------------------------------===// - -#define _LIBCPP_BUILDING_LIBRARY -#include "__cxxabi_config.h" -#include <new> -#include <cstdlib> - -#if !defined(_THROW_BAD_ALLOC) || !defined(_NOEXCEPT) || !defined(_LIBCXXABI_WEAK) -#error The _THROW_BAD_ALLOC, _NOEXCEPT, and _LIBCXXABI_WEAK libc++ macros must \ - already be defined by libc++. -#endif -// Implement all new and delete operators as weak definitions -// in this shared library, so that they can be overridden by programs -// that define non-weak copies of the functions. - -_LIBCXXABI_WEAK -void * -operator new(std::size_t size) _THROW_BAD_ALLOC -{ - if (size == 0) - size = 1; - void* p; - while ((p = ::malloc(size)) == 0) - { - // If malloc fails and there is a new_handler, - // call it to try free up memory. - std::new_handler nh = std::get_new_handler(); - if (nh) - nh(); - else -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_alloc(); -#else - break; -#endif - } - return p; -} - -_LIBCXXABI_WEAK -void* -operator new(size_t size, const std::nothrow_t&) _NOEXCEPT -{ - void* p = 0; -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - p = ::operator new(size); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - } -#endif // _LIBCXXABI_NO_EXCEPTIONS - return p; -} - -_LIBCXXABI_WEAK -void* -operator new[](size_t size) _THROW_BAD_ALLOC -{ - return ::operator new(size); -} - -_LIBCXXABI_WEAK -void* -operator new[](size_t size, const std::nothrow_t&) _NOEXCEPT -{ - void* p = 0; -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - p = ::operator new[](size); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - } -#endif // _LIBCXXABI_NO_EXCEPTIONS - return p; -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr) _NOEXCEPT -{ - if (ptr) - ::free(ptr); -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr, const std::nothrow_t&) _NOEXCEPT -{ - ::operator delete(ptr); -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr, size_t) _NOEXCEPT -{ - ::operator delete(ptr); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr) _NOEXCEPT -{ - ::operator delete(ptr); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr, const std::nothrow_t&) _NOEXCEPT -{ - ::operator delete[](ptr); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr, size_t) _NOEXCEPT -{ - ::operator delete[](ptr); -} - -#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) - -_LIBCXXABI_WEAK -void * -operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC -{ - if (size == 0) - size = 1; - if (static_cast<size_t>(alignment) < sizeof(void*)) - alignment = std::align_val_t(sizeof(void*)); - void* p; -#if defined(_LIBCPP_WIN32API) - while ((p = _aligned_malloc(size, static_cast<size_t>(alignment))) == nullptr) -#else - while (::posix_memalign(&p, static_cast<size_t>(alignment), size) != 0) -#endif - { - // If posix_memalign fails and there is a new_handler, - // call it to try free up memory. - std::new_handler nh = std::get_new_handler(); - if (nh) - nh(); - else { -#ifndef _LIBCXXABI_NO_EXCEPTIONS - throw std::bad_alloc(); -#else - p = nullptr; // posix_memalign doesn't initialize 'p' on failure - break; -#endif - } - } - return p; -} - -_LIBCXXABI_WEAK -void* -operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT -{ - void* p = 0; -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - p = ::operator new(size, alignment); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - } -#endif // _LIBCXXABI_NO_EXCEPTIONS - return p; -} - -_LIBCXXABI_WEAK -void* -operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC -{ - return ::operator new(size, alignment); -} - -_LIBCXXABI_WEAK -void* -operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT -{ - void* p = 0; -#ifndef _LIBCXXABI_NO_EXCEPTIONS - try - { -#endif // _LIBCXXABI_NO_EXCEPTIONS - p = ::operator new[](size, alignment); -#ifndef _LIBCXXABI_NO_EXCEPTIONS - } - catch (...) - { - } -#endif // _LIBCXXABI_NO_EXCEPTIONS - return p; -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr, std::align_val_t) _NOEXCEPT -{ - if (ptr) -#if defined(_LIBCPP_WIN32API) - ::_aligned_free(ptr); -#else - ::free(ptr); -#endif -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT -{ - ::operator delete(ptr, alignment); -} - -_LIBCXXABI_WEAK -void -operator delete(void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT -{ - ::operator delete(ptr, alignment); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr, std::align_val_t alignment) _NOEXCEPT -{ - ::operator delete(ptr, alignment); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) _NOEXCEPT -{ - ::operator delete[](ptr, alignment); -} - -_LIBCXXABI_WEAK -void -operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT -{ - ::operator delete[](ptr, alignment); -} - -#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION diff --git a/lib/libcxxabi/src/stdlib_stdexcept.cpp b/lib/libcxxabi/src/stdlib_stdexcept.cpp deleted file mode 100644 index e3b7cd40658..00000000000 --- a/lib/libcxxabi/src/stdlib_stdexcept.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===------------------------ stdexcept.cpp -------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "include/refstring.h" -#include "stdexcept" -#include "new" -#include <cstdlib> -#include <cstring> -#include <cstdint> -#include <cstddef> - -static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), ""); - -namespace std // purposefully not using versioning namespace -{ - -logic_error::~logic_error() _NOEXCEPT {} - -const char* -logic_error::what() const _NOEXCEPT -{ - return __imp_.c_str(); -} - -runtime_error::~runtime_error() _NOEXCEPT {} - -const char* -runtime_error::what() const _NOEXCEPT -{ - return __imp_.c_str(); -} - -domain_error::~domain_error() _NOEXCEPT {} -invalid_argument::~invalid_argument() _NOEXCEPT {} -length_error::~length_error() _NOEXCEPT {} -out_of_range::~out_of_range() _NOEXCEPT {} - -range_error::~range_error() _NOEXCEPT {} -overflow_error::~overflow_error() _NOEXCEPT {} -underflow_error::~underflow_error() _NOEXCEPT {} - -} // std diff --git a/lib/libcxxabi/src/stdlib_typeinfo.cpp b/lib/libcxxabi/src/stdlib_typeinfo.cpp deleted file mode 100644 index 9313be04a39..00000000000 --- a/lib/libcxxabi/src/stdlib_typeinfo.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//===----------------------------- typeinfo.cpp ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include <typeinfo> - -namespace std -{ - -// type_info - -type_info::~type_info() -{ -} - -// bad_cast - -bad_cast::bad_cast() _NOEXCEPT -{ -} - -bad_cast::~bad_cast() _NOEXCEPT -{ -} - -const char* -bad_cast::what() const _NOEXCEPT -{ - return "std::bad_cast"; -} - -// bad_typeid - -bad_typeid::bad_typeid() _NOEXCEPT -{ -} - -bad_typeid::~bad_typeid() _NOEXCEPT -{ -} - -const char* -bad_typeid::what() const _NOEXCEPT -{ - return "std::bad_typeid"; -} - -} // std |