Merge 1839f48 for LLVM update to 339409 Change-Id: I6c070048b836fef72d3d13531dadebc68a775707
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1488737..0eeb4b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -21,7 +21,7 @@ project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 7.0.0svn) + set(PACKAGE_VERSION 8.0.0svn) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") @@ -84,6 +84,20 @@ option(LIBCXXABI_ENABLE_SHARED "Build libc++abi as a shared library." ON) option(LIBCXXABI_ENABLE_STATIC "Build libc++abi as a static library." ON) +cmake_dependent_option(LIBCXXABI_INSTALL_STATIC_LIBRARY + "Install the static libc++abi library." ON + "LIBCXXABI_ENABLE_STATIC;LIBCXXABI_INSTALL_LIBRARY" OFF) +cmake_dependent_option(LIBCXXABI_INSTALL_SHARED_LIBRARY + "Install the shared libc++abi library." ON + "LIBCXXABI_ENABLE_SHARED;LIBCXXABI_INSTALL_LIBRARY" OFF) + +cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY + "Statically link the LLVM unwinder to static library" ON + "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_STATIC" OFF) +cmake_dependent_option(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY + "Statically link the LLVM unwinder to shared library" ON + "LIBCXXABI_ENABLE_STATIC_UNWINDER;LIBCXXABI_ENABLE_SHARED" OFF) + option(LIBCXXABI_BAREMETAL "Build libc++abi for baremetal targets." OFF) # The default terminate handler attempts to demangle uncaught exceptions, which # causes extra I/O and demangling code to be pulled in. @@ -110,12 +124,13 @@ find_path( LIBCXXABI_LIBCXX_INCLUDES - vector + __config PATHS ${LIBCXXABI_LIBCXX_INCLUDES} ${LIBCXXABI_LIBCXX_PATH}/include ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBCXX_INCLUDES} ${LIBCXXABI_LIBCXX_INCLUDE_DIRS} ${LLVM_INCLUDE_DIR}/c++/v1 + NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) @@ -154,19 +169,22 @@ set(LIBCXXABI_COMPILER ${CMAKE_CXX_COMPILER}) set(LIBCXXABI_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(LIBCXXABI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) -if (LLVM_LIBRARY_OUTPUT_INTDIR) + +string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" CLANG_VERSION + ${PACKAGE_VERSION}) + +if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE) + set(DEFAULT_INSTALL_PREFIX lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/${LLVM_DEFAULT_TARGET_TRIPLE}/) + set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/${LLVM_DEFAULT_TARGET_TRIPLE}/lib${LIBCXXABI_LIBDIR_SUFFIX}) +elseif(LLVM_LIBRARY_OUTPUT_INTDIR) set(LIBCXXABI_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}) else() set(LIBCXXABI_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXXABI_LIBDIR_SUFFIX}) endif() -set(LIBCXXABI_INSTALL_PREFIX "" CACHE STRING +set(LIBCXXABI_INSTALL_PREFIX ${DEFAULT_INSTALL_PREFIX} CACHE STRING "Define libc++abi destination prefix.") -if (NOT LIBCXXABI_INSTALL_PREFIX MATCHES "^$|.*/") - message(FATAL_ERROR "LIBCXXABI_INSTALL_PREFIX has to end with \"/\".") -endif() - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXXABI_LIBRARY_DIR})
diff --git a/LICENSE.TXT b/LICENSE.TXT index f333f1f..f1f163f 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT
@@ -14,7 +14,7 @@ University of Illinois/NCSA Open Source License -Copyright (c) 2009-2017 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT All rights reserved.
diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake index 395c21a..945de58 100644 --- a/cmake/Modules/HandleCompilerRT.cmake +++ b/cmake/Modules/HandleCompilerRT.cmake
@@ -14,6 +14,7 @@ OUTPUT_VARIABLE LIBRARY_FILE ) string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}") if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}") message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}") @@ -37,6 +38,7 @@ OUTPUT_VARIABLE LIBRARY_DIR ) string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR) + file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR) set(LIBRARY_DIR "${LIBRARY_DIR}/darwin") else() set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBCXXABI_COMPILE_FLAGS} @@ -47,6 +49,7 @@ OUTPUT_VARIABLE LIBRARY_FILE ) string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE) + file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE) get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY) endif() if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
diff --git a/cmake/Modules/HandleOutOfTreeLLVM.cmake b/cmake/Modules/HandleOutOfTreeLLVM.cmake index ed0b527..e50d026 100644 --- a/cmake/Modules/HandleOutOfTreeLLVM.cmake +++ b/cmake/Modules/HandleOutOfTreeLLVM.cmake
@@ -46,10 +46,11 @@ OUTPUT_VARIABLE CONFIG_OUTPUT ERROR_QUIET) if(NOT HAD_ERROR) - string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH) + string(STRIP "${CONFIG_OUTPUT}" LLVM_CMAKE_PATH_FROM_LLVM_CONFIG) + file(TO_CMAKE_PATH "${LLVM_CMAKE_PATH_FROM_LLVM_CONFIG}" LLVM_CMAKE_PATH) else() - set(LLVM_CMAKE_PATH - "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") + file(TO_CMAKE_PATH "${LLVM_BINARY_DIR}" LLVM_BINARY_DIR_CMAKE_STYLE) + set(LLVM_CMAKE_PATH "${LLVM_BINARY_DIR_CMAKE_STYLE}/lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm") endif() else() set(LLVM_FOUND OFF)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a929cf..776c512 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -61,12 +61,19 @@ # Prefer using the in-tree version of libunwind, either shared or static. If # none are found fall back to using -lunwind. # FIXME: Is it correct to prefer the static version of libunwind? - if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_LIBRARIES unwind_shared) - elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND)) - list(APPEND LIBCXXABI_LIBRARIES unwind_static) + 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_LIBRARIES unwind) + 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) @@ -122,15 +129,13 @@ POSITION_INDEPENDENT_CODE ON) -set(LIBCXXABI_TARGETS) - # 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}) + target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_SHARED_LIBRARIES}) set_target_properties(cxxabi_shared PROPERTIES CXX_EXTENSIONS @@ -149,19 +154,22 @@ "1" VERSION "1.0") - list(APPEND LIBCXXABI_TARGETS "cxxabi_shared") + 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_ENABLE_STATIC_UNWINDER) + 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}) + target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_STATIC_LIBRARIES}) set_target_properties(cxxabi_static PROPERTIES CXX_EXTENSIONS @@ -176,14 +184,17 @@ "c++abi" POSITION_INDEPENDENT_CODE ON) - list(APPEND LIBCXXABI_TARGETS "cxxabi_static") + 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_TARGETS}) +add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS}) if (LIBCXXABI_INSTALL_LIBRARY) - install(TARGETS ${LIBCXXABI_TARGETS} + 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 )
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp index d70ffdf..3a7ee06 100644 --- a/src/cxa_demangle.cpp +++ b/src/cxa_demangle.cpp
@@ -15,150 +15,26 @@ #include "__cxxabi_config.h" -#include <vector> -#include <algorithm> -#include <numeric> +#include "demangle/Compiler.h" +#include "demangle/StringView.h" +#include "demangle/Utility.h" + #include <cassert> +#include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> -#include <cctype> - -#ifdef _MSC_VER -// snprintf is implemented in VS 2015 -#if _MSC_VER < 1900 -#define snprintf _snprintf_s -#endif -#endif - -#ifndef NDEBUG -#if __has_attribute(noinline) && __has_attribute(used) -#define DUMP_METHOD __attribute__((noinline,used)) -#else -#define DUMP_METHOD -#endif -#endif +#include <numeric> +#include <utility> +#include <vector> 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() : First(nullptr), Last(nullptr) {} - - StringView substr(size_t From, size_t To) { - if (To >= size()) - To = size() - 1; - if (From >= size()) - From = size() - 1; - return StringView(First + From, First + To); - } - - StringView dropFront(size_t N) const { - if (N >= size()) - N = size() - 1; - return StringView(First + N, Last); - } - - bool startsWith(StringView Str) const { - if (Str.size() > size()) - return false; - return std::equal(Str.begin(), Str.end(), begin()); - } - - const char &operator[](size_t Idx) const { return *(begin() + Idx); } - - const char *begin() const { return First; } - const char *end() const { return Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - bool empty() const { return First == Last; } -}; - -bool operator==(const StringView &LHS, const StringView &RHS) { - return LHS.size() == RHS.size() && - std::equal(LHS.begin(), LHS.end(), RHS.begin()); -} - -// Stream that AST nodes write their string representation into after the AST -// has been parsed. -class OutputStream { - char *Buffer; - size_t CurrentPosition; - size_t BufferCapacity; - - // Ensure there is at least n more positions in buffer. - void grow(size_t N) { - if (N + CurrentPosition >= BufferCapacity) { - BufferCapacity *= 2; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; - Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); - } - } - -public: - OutputStream(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = 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); - memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; - return *this; - } - - OutputStream &operator+=(char C) { - grow(1); - Buffer[CurrentPosition++] = C; - return *this; - } - - 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; -public: - SwapAndRestore(T& Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); - } - ~SwapAndRestore() { Restore = std::move(OriginalValue); } - - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; +enum : int { + demangle_unknown_error = -4, + demangle_invalid_args = -3, + demangle_invalid_mangled_name = -2, + demangle_memory_alloc_failure = -1, + demangle_success = 0, }; // Base class of all AST nodes. The AST is built by the parser, then is @@ -178,8 +54,7 @@ KEnableIfAttr, KObjCProtoName, KPointerType, - KLValueReferenceType, - KRValueReferenceType, + KReferenceType, KPointerToMemberType, KArrayType, KFunctionType, @@ -260,6 +135,12 @@ 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) @@ -272,7 +153,7 @@ // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default - // implemenation. + // implementation. virtual void printRight(OutputStream &) const {} virtual StringView getBaseName() const { return StringView(); } @@ -570,60 +451,64 @@ } }; -class LValueReferenceType final : public Node { - const Node *Pointee; - -public: - LValueReferenceType(Node *Pointee_) - : Node(KLValueReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} - - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); - } - - void printLeft(OutputStream &s) const override { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "(&"; - else - s += "&"; - } - void printRight(OutputStream &s) const override { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); - } +enum class ReferenceKind { + LValue, + RValue, }; -class RValueReferenceType final : public Node { +// 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: - RValueReferenceType(Node *Pointee_) - : Node(KRValueReferenceType, Pointee_->RHSComponentCache), - Pointee(Pointee_) {} + ReferenceType(Node *Pointee_, ReferenceKind RK_) + : Node(KReferenceType, Pointee_->RHSComponentCache), + Pointee(Pointee_), RK(RK_) {} bool hasRHSComponentSlow(OutputStream &S) const override { return Pointee->hasRHSComponent(S); } void printLeft(OutputStream &s) const override { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) + 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 (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "(&&"; - else - s += "&&"; - } + if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) + s += "("; + s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + } void printRight(OutputStream &s) const override { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) + 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 += ")"; - Pointee->printRight(s); + Collapsed.second->printRight(s); } }; @@ -748,7 +633,7 @@ bool hasRHSComponentSlow(OutputStream &) const override { return true; } bool hasFunctionSlow(OutputStream &) const override { return true; } - // Handle C++'s ... quirky decl grammer by using the left & right + // 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 @@ -1042,6 +927,11 @@ 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); @@ -1057,7 +947,7 @@ } }; -/// A variadic template argument. This node represents an occurance of +/// 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 @@ -1169,6 +1059,12 @@ 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) @@ -1890,17 +1786,21 @@ static constexpr size_t AllocSize = 4096; static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta); - alignas(16) char InitialBuffer[AllocSize]; + alignas(long double) char InitialBuffer[AllocSize]; BlockMeta* BlockList = nullptr; void grow() { - char* NewMeta = new char[AllocSize]; + 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*>(new char[NBytes]); + 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); } @@ -1926,7 +1826,7 @@ BlockMeta* Tmp = BlockList; BlockList = BlockList->Next; if (reinterpret_cast<char*>(Tmp) != InitialBuffer) - delete[] reinterpret_cast<char*>(Tmp); + std::free(Tmp); } BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; } @@ -1956,10 +1856,15 @@ 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 + } else { First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } Last = First + S; Cap = First + NewCap; } @@ -2053,7 +1958,7 @@ const char *Last; // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser colapses multiple names into new nodes to construct + // 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; @@ -2927,7 +2832,7 @@ // <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> +// ::= [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> @@ -2977,7 +2882,7 @@ return SoFar; } - // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> + // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> if (std::isdigit(look())) { do { Node *Qual = parseSimpleId(); @@ -3558,7 +3463,7 @@ Node *Ref = parseType(); if (Ref == nullptr) return nullptr; - Result = make<LValueReferenceType>(Ref); + Result = make<ReferenceType>(Ref, ReferenceKind::LValue); break; } // ::= O <type> # r-value reference (C++11) @@ -3567,7 +3472,7 @@ Node *Ref = parseType(); if (Ref == nullptr) return nullptr; - Result = make<RValueReferenceType>(Ref); + Result = make<ReferenceType>(Ref, ReferenceKind::RValue); break; } // ::= C <type> # complex pair (C99) @@ -5030,6 +4935,8 @@ 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); @@ -5058,33 +4965,25 @@ } // unnamed namespace -enum { - unknown_error = -4, - invalid_args = -3, - invalid_mangled_name = -2, - memory_alloc_failure = -1, - 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 = invalid_args; + *Status = demangle_invalid_args; return nullptr; } - int InternalStatus = success; + int InternalStatus = demangle_success; Db Parser(MangledName, MangledName + std::strlen(MangledName)); OutputStream S; Node *AST = Parser.parse(); if (AST == nullptr) - InternalStatus = invalid_mangled_name; + InternalStatus = demangle_invalid_mangled_name; else if (initializeOutputStream(Buf, N, S, 1024)) - InternalStatus = memory_alloc_failure; + InternalStatus = demangle_memory_alloc_failure; else { assert(Parser.ForwardTemplateRefs.empty()); AST->print(S); @@ -5096,6 +4995,6 @@ if (Status) *Status = InternalStatus; - return InternalStatus == success ? Buf : nullptr; + return InternalStatus == demangle_success ? Buf : nullptr; } } // __cxxabiv1
diff --git a/src/cxa_personality.cpp b/src/cxa_personality.cpp index 7f857fa..6759d8a 100644 --- a/src/cxa_personality.cpp +++ b/src/cxa_personality.cpp
@@ -23,6 +23,16 @@ #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: @@ -934,12 +944,16 @@ */ #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) { @@ -1022,6 +1036,17 @@ // 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" 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*,
diff --git a/src/demangle/Compiler.h b/src/demangle/Compiler.h new file mode 100644 index 0000000..e5f3c72 --- /dev/null +++ b/src/demangle/Compiler.h
@@ -0,0 +1,34 @@ +//===--- 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/src/demangle/StringView.h b/src/demangle/StringView.h new file mode 100644 index 0000000..986f2de --- /dev/null +++ b/src/demangle/StringView.h
@@ -0,0 +1,98 @@ +//===--- 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/src/demangle/Utility.h b/src/demangle/Utility.h new file mode 100644 index 0000000..3909243 --- /dev/null +++ b/src/demangle/Utility.h
@@ -0,0 +1,191 @@ +//===--- 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_; + } + + /// Create an OutputStream from a buffer and a size. If either of these are + /// null a buffer is allocated. + static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) { + OutputStream Result; + + if (!StartBuf || !Size) { + StartBuf = static_cast<char *>(std::malloc(AllocSize)); + if (StartBuf == nullptr) + std::terminate(); + Size = &AllocSize; + } + + Result.reset(StartBuf, *Size); + return Result; + } + + /// 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; +}; + +} // namespace + +#endif
diff --git a/src/stdlib_exception.cpp b/src/stdlib_exception.cpp index a8f71ab..6c09102 100644 --- a/src/stdlib_exception.cpp +++ b/src/stdlib_exception.cpp
@@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #define _LIBCPP_BUILDING_LIBRARY -#define _LIBCPP_BUILDING_NEW #include <new> #include <exception>
diff --git a/src/stdlib_new_delete.cpp b/src/stdlib_new_delete.cpp index 0e85f6a..686ad07 100644 --- a/src/stdlib_new_delete.cpp +++ b/src/stdlib_new_delete.cpp
@@ -9,7 +9,6 @@ // This file implements the new and delete operators. //===----------------------------------------------------------------------===// -#define _LIBCPP_BUILDING_NEW #define _LIBCPP_BUILDING_LIBRARY #include "__cxxabi_config.h" #include <new>
diff --git a/test/catch_member_function_pointer_02.pass.cpp b/test/catch_member_function_pointer_02.pass.cpp index 6bd9e6f..29f02bd 100644 --- a/test/catch_member_function_pointer_02.pass.cpp +++ b/test/catch_member_function_pointer_02.pass.cpp
@@ -13,7 +13,7 @@ // GCC 7 and 8 support noexcept function types but this test still fails. // This is likely a bug in their implementation. Investigation needed. -// XFAIL: gcc-7, gcc-8 +// XFAIL: gcc-7, gcc-8, gcc-9 #include <cassert>
diff --git a/test/cxa_bad_cast.pass.cpp b/test/cxa_bad_cast.pass.cpp index d2c3bf9..9b6bff4 100644 --- a/test/cxa_bad_cast.pass.cpp +++ b/test/cxa_bad_cast.pass.cpp
@@ -21,7 +21,7 @@ class Derived : public Base {}; -Derived &test_bad_cast(Base b) { +Derived &test_bad_cast(Base& b) { return dynamic_cast<Derived&>(b); }
diff --git a/test/libcxxabi/test/config.py b/test/libcxxabi/test/config.py index f294c8b..abec67f 100644 --- a/test/libcxxabi/test/config.py +++ b/test/libcxxabi/test/config.py
@@ -10,6 +10,7 @@ import sys from libcxx.test.config import Configuration as LibcxxConfiguration +from libcxx.test.config import intMacroValue class Configuration(LibcxxConfiguration): @@ -34,7 +35,7 @@ super(Configuration, self).configure_obj_root() def has_cpp_feature(self, feature, required_value): - return int(self.cxx.dumpMacros().get('__cpp_' + feature, 0)) >= required_value + return intMacroValue(self.cxx.dumpMacros().get('__cpp_' + feature, '0')) >= required_value def configure_features(self): super(Configuration, self).configure_features()
diff --git a/test/test_demangle.pass.cpp b/test/test_demangle.pass.cpp index ea7a0fa..7c1fd2d 100644 --- a/test/test_demangle.pass.cpp +++ b/test/test_demangle.pass.cpp
@@ -29749,6 +29749,12 @@ {"_Z5foldlIJLi1ELi2ELi3EEEv1AIXflplT_EE", "void foldl<1, 2, 3>(A<(... + (1, 2, 3))>)"}, {"_Z5foldrIJLi1ELi2ELi3EEEv1AIXfrplT_EE", "void foldr<1, 2, 3>(A<((1, 2, 3) + ...)>)"}, {"_ZN7PartialIJLi1ELi2EEE5foldrIJLi3ELi4EEEEv1AIXplLi1EplLi2EfRplT_plLi1EplLi2EfrplT_EE", "void Partial<1, 2>::foldr<3, 4>(A<(1) + ((2) + (((3, 4) + ... + (1) + ((2) + (((3, 4) + ...))))))>)"}, + + // reference collapsing: + {"_Z1fIR1SEiOT_", "int f<S&>(S&)"}, + {"_Z1fIJR1SS0_EEiDpOT_", "int f<S&, S>(S&, S&&)"}, + + {"___Z3foo_block_invoke.25", "invocation function for block in foo"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]);