diff options
author | Stephen Hines <srhines@google.com> | 2018-07-09 10:00:10 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2018-07-09 10:00:10 -0700 |
commit | 3ec3c6396b642d537717f981ba3615286711951f (patch) | |
tree | 11e09e6d00958047f684de1d23fc91c223f1e27e | |
parent | 77f176fe2ffb0f38e1aea675d68fce882e8e5bcd (diff) | |
parent | e0330b61d74b898ee64922d0a3d50c3562f6ddb1 (diff) | |
download | libcxxabi-3ec3c6396b642d537717f981ba3615286711951f.tar.gz |
Merge e0330b6 for LLVM update to 333878
Change-Id: I14188f576bffec5ce6096a6671e71a7ec94b1f25
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | include/__cxxabi_config.h | 10 | ||||
-rw-r--r-- | src/cxa_default_handlers.cpp | 17 | ||||
-rw-r--r-- | src/cxa_demangle.cpp | 302 | ||||
-rw-r--r-- | src/cxa_exception.cpp | 11 | ||||
-rw-r--r-- | src/cxa_handlers.cpp | 22 | ||||
-rw-r--r-- | src/include/atomic_support.h | 181 | ||||
-rw-r--r-- | src/include/refstring.h | 9 | ||||
-rw-r--r-- | src/private_typeinfo.cpp | 69 | ||||
-rw-r--r-- | test/dynamic_cast.pass.cpp | 154 | ||||
-rw-r--r-- | test/libcxxabi/test/config.py | 5 | ||||
-rw-r--r-- | test/test_demangle.pass.cpp | 11 | ||||
-rw-r--r-- | test/test_exception_storage.pass.cpp | 5 |
13 files changed, 679 insertions, 123 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 35eb130..1488737 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ else() set(LIBCXXABI_LIBCXX_SRC_DIRS "${LLVM_MAIN_SRC_DIR}/projects/libcxx" "${LLVM_MAIN_SRC_DIR}/runtimes/libcxx" + "${LLVM_MAIN_SRC_DIR}/../libcxx" ) endif() @@ -386,6 +387,10 @@ endif() # Prevent libc++abi from having library dependencies on libc++ add_definitions(-D_LIBCPP_DISABLE_EXTERN_TEMPLATE) +# Bring back `std::unexpected`, which is removed in C++17, to support +# pre-C++17. +add_definitions(-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) + if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif() @@ -426,6 +431,7 @@ if (LIBCXXABI_USE_LLVM_UNWINDER OR LLVM_NATIVE_ARCH MATCHES ARM) ${CMAKE_BINARY_DIR}/${LIBCXXABI_LIBUNWIND_INCLUDES} ${LLVM_MAIN_SRC_DIR}/projects/libunwind/include ${LLVM_MAIN_SRC_DIR}/runtimes/libunwind/include + ${LLVM_MAIN_SRC_DIR}/../libunwind/include NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) diff --git a/include/__cxxabi_config.h b/include/__cxxabi_config.h index 65b1961..46f5914 100644 --- a/include/__cxxabi_config.h +++ b/include/__cxxabi_config.h @@ -60,4 +60,14 @@ #define _LIBCXXABI_WEAK __attribute__((__weak__)) #endif +#if defined(__clang__) +#define _LIBCXXABI_COMPILER_CLANG +#endif + +#if __has_attribute(__no_sanitize__) && defined(_LIBCXXABI_COMPILER_CLANG) +#define _LIBCXXABI_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +#define _LIBCXXABI_NO_CFI +#endif + #endif // ____CXXABI_CONFIG_H diff --git a/src/cxa_default_handlers.cpp b/src/cxa_default_handlers.cpp index 8231139..0fa169f 100644 --- a/src/cxa_default_handlers.cpp +++ b/src/cxa_default_handlers.cpp @@ -18,6 +18,7 @@ #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"; @@ -101,10 +102,6 @@ std::terminate_handler __cxa_terminate_handler = default_terminate_handler; _LIBCXXABI_DATA_VIS std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; -// In the future these will become: -// std::atomic<std::terminate_handler> __cxa_terminate_handler(default_terminate_handler); -// std::atomic<std::unexpected_handler> __cxa_unexpected_handler(default_unexpected_handler); - namespace std { @@ -113,10 +110,8 @@ set_unexpected(unexpected_handler func) _NOEXCEPT { if (func == 0) func = default_unexpected_handler; - return __atomic_exchange_n(&__cxa_unexpected_handler, func, - __ATOMIC_ACQ_REL); -// Using of C++11 atomics this should be rewritten -// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel); + return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func, + _AO_Acq_Rel); } terminate_handler @@ -124,10 +119,8 @@ set_terminate(terminate_handler func) _NOEXCEPT { if (func == 0) func = default_terminate_handler; - return __atomic_exchange_n(&__cxa_terminate_handler, func, - __ATOMIC_ACQ_REL); -// Using of C++11 atomics this should be rewritten -// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel); + return __libcpp_atomic_exchange(&__cxa_terminate_handler, func, + _AO_Acq_Rel); } } diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp index 9253e83..d70ffdf 100644 --- a/src/cxa_demangle.cpp +++ b/src/cxa_demangle.cpp @@ -10,7 +10,6 @@ // FIXME: (possibly) incomplete list of features that clang mangles that this // file does not yet support: // - C++ modules TS -// - All C++14 and C++17 features #define _LIBCPP_NO_EXCEPTIONS @@ -105,6 +104,12 @@ class OutputStream { 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. @@ -161,6 +166,7 @@ public: class Node { public: enum Kind : unsigned char { + KNodeArrayNode, KDotSuffix, KVendorExtQualType, KQualType, @@ -184,7 +190,8 @@ public: KSpecialName, KCtorVtableSpecialName, KQualifiedName, - KEmptyName, + KNestedName, + KLocalName, KVectorType, KParameterPack, KTemplateArgumentPack, @@ -323,6 +330,14 @@ public: } }; +struct NodeArrayNode : Node { + NodeArray Array; + NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {} + void printLeft(OutputStream &S) const override { + Array.printWithComma(S); + } +}; + class DotSuffix final : public Node { const Node *Prefix; const StringView Suffix; @@ -462,11 +477,11 @@ public: } }; -class AbiTagAttr final : public Node { - const Node* Base; +struct AbiTagAttr : Node { + Node *Base; StringView Tag; -public: - AbiTagAttr(const Node* Base_, StringView Tag_) + + AbiTagAttr(Node* Base_, StringView Tag_) : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache, Base_->FunctionCache), Base(Base_), Tag(Tag_) {} @@ -796,8 +811,8 @@ public: }; class FunctionEncoding final : public Node { - const Node *Ret; - const Node *Name; + Node *Ret; + Node *Name; NodeArray Params; Node *Attrs; Qualifiers CVQuals; @@ -812,6 +827,11 @@ public: Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), CVQuals(CVQuals_), RefQual(RefQual_) {} + Qualifiers getCVQuals() const { return CVQuals; } + FunctionRefQual getRefQual() const { return RefQual; } + NodeArray getParams() const { return Params; } + Node *getReturnType() const { return Ret; } + bool hasRHSComponentSlow(OutputStream &) const override { return true; } bool hasFunctionSlow(OutputStream &) const override { return true; } @@ -893,6 +913,36 @@ public: } }; +struct NestedName : Node { + Node *Qual; + Node *Name; + + NestedName(Node *Qual_, Node *Name_) + : Node(KNestedName), Qual(Qual_), Name(Name_) {} + + StringView getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputStream &S) const override { + Qual->print(S); + S += "::"; + Name->print(S); + } +}; + +struct LocalName : Node { + Node *Encoding; + Node *Entity; + + LocalName(Node *Encoding_, Node *Entity_) + : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {} + + void printLeft(OutputStream &S) const override { + Encoding->print(S); + S += "::"; + Entity->print(S); + } +}; + class QualifiedName final : public Node { // qualifier::name const Node *Qualifier; @@ -911,12 +961,6 @@ public: } }; -class EmptyName : public Node { -public: - EmptyName() : Node(KEmptyName) {} - void printLeft(OutputStream &) const override {} -}; - class VectorType final : public Node { const Node *BaseType; const NodeOrString Dimension; @@ -1140,12 +1184,11 @@ struct ForwardTemplateReference : Node { } }; -class NameWithTemplateArgs final : public Node { +struct NameWithTemplateArgs : Node { // name<template_args> Node *Name; Node *TemplateArgs; -public: NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_) : Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {} @@ -1172,10 +1215,9 @@ public: } }; -class StdQualifiedName final : public Node { +struct StdQualifiedName : Node { Node *Child; -public: StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} StringView getBaseName() const override { return Child->getBaseName(); } @@ -1686,6 +1728,55 @@ public: } }; +struct FoldExpr : Expr { + Node *Pack, *Init; + StringView OperatorName; + bool IsLeftFold; + + FoldExpr(bool IsLeftFold_, StringView OperatorName_, Node *Pack_, Node *Init_) + : Pack(Pack_), Init(Init_), OperatorName(OperatorName_), + IsLeftFold(IsLeftFold_) {} + + void printLeft(OutputStream &S) const override { + auto PrintPack = [&] { + S += '('; + ParameterPackExpansion(Pack).print(S); + S += ')'; + }; + + S += '('; + + if (IsLeftFold) { + // init op ... op pack + if (Init != nullptr) { + Init->print(S); + S += ' '; + S += OperatorName; + S += ' '; + } + // ... op pack + S += "... "; + S += OperatorName; + S += ' '; + PrintPack(); + } else { // !IsLeftFold + // pack op ... + PrintPack(); + S += ' '; + S += OperatorName; + S += " ..."; + // pack op ... op init + if (Init != nullptr) { + S += ' '; + S += OperatorName; + S += ' '; + Init->print(S); + } + } + S += ')'; + } +}; + class ThrowExpr : public Expr { const Node *Op; @@ -1830,14 +1921,17 @@ public: BlockList->Current - N); } - ~BumpPointerAllocator() { + void reset() { while (BlockList) { BlockMeta* Tmp = BlockList; BlockList = BlockList->Next; if (reinterpret_cast<char*>(Tmp) != InitialBuffer) delete[] reinterpret_cast<char*>(Tmp); } + BlockList = new (InitialBuffer) BlockMeta{nullptr, 0}; } + + ~BumpPointerAllocator() { reset(); } }; template <class T, size_t N> @@ -1985,6 +2079,18 @@ struct Db { Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {} + void reset(const char *First_, const char *Last_) { + First = First_; + Last = Last_; + Names.clear(); + Subs.clear(); + TemplateParams.clear(); + ParsingLambdaParams = false; + TryToParseTemplateArgs = true; + PermitForwardTemplateReferences = false; + ASTAllocator.reset(); + } + template <class T, class... Args> T *make(Args &&... args) { return new (ASTAllocator.allocate(sizeof(T))) T(std::forward<Args>(args)...); @@ -2054,6 +2160,7 @@ struct Db { Node *parseNewExpr(); Node *parseConversionExpr(); Node *parseBracedExpr(); + Node *parseFoldExpr(); /// Parse the <type> production. Node *parseType(); @@ -2178,7 +2285,7 @@ Node *Db::parseLocalName(NameState *State) { if (consumeIf('s')) { First = parse_discriminator(First, Last); - return make<QualifiedName>(Encoding, make<NameType>("string literal")); + return make<LocalName>(Encoding, make<NameType>("string literal")); } if (consumeIf('d')) { @@ -2188,14 +2295,14 @@ Node *Db::parseLocalName(NameState *State) { Node *N = parseName(State); if (N == nullptr) return nullptr; - return make<QualifiedName>(Encoding, N); + return make<LocalName>(Encoding, N); } Node *Entity = parseName(State); if (Entity == nullptr) return nullptr; First = parse_discriminator(First, Last); - return make<QualifiedName>(Encoding, Entity); + return make<LocalName>(Encoding, Entity); } // <unscoped-name> ::= <unqualified-name> @@ -2630,6 +2737,8 @@ Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) { // ::= <prefix> <data-member-prefix> // extension ::= L // +// <data-member-prefix> := <member source-name> [<template-args>] M +// // <template-prefix> ::= <prefix> <template unqualified-name> // ::= <template-param> // ::= <substitution> @@ -2649,7 +2758,7 @@ Node *Db::parseNestedName(NameState *State) { Node *SoFar = nullptr; auto PushComponent = [&](Node *Comp) { - if (SoFar) SoFar = make<QualifiedName>(SoFar, Comp); + if (SoFar) SoFar = make<NestedName>(SoFar, Comp); else SoFar = Comp; if (State) State->EndsWithTemplateArgs = false; }; @@ -2660,6 +2769,13 @@ Node *Db::parseNestedName(NameState *State) { 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') { Node *TP = parseTemplateParam(); @@ -3789,6 +3905,76 @@ Node *Db::parseBracedExpr() { return 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> +Node *Db::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 = parseExpr(), *Init = nullptr; + if (Pack == nullptr) + return nullptr; + if (HasInitializer) { + Init = 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> @@ -3821,6 +4007,7 @@ Node *Db::parseBracedExpr() { // ::= 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) @@ -3842,8 +4029,12 @@ Node *Db::parseExpr() { return parseExprPrimary(); case 'T': return parseTemplateParam(); - case 'f': - return parseFunctionParam(); + case 'f': { + // Disambiguate a fold expression from a <function-param>. + if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) + return parseFunctionParam(); + return parseFoldExpr(); + } case 'a': switch (First[1]) { case 'a': @@ -4221,9 +4412,22 @@ Node *Db::parseExpr() { Node *FP = parseFunctionParam(); if (FP == nullptr) return nullptr; - return make<EnclosingExpr>("sizeof...", FP, ")"); + return make<EnclosingExpr>("sizeof... (", FP, ")"); } return nullptr; + case 'P': { + First += 2; + size_t ArgsBegin = Names.size(); + while (!consumeIf('E')) { + Node *Arg = parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + Names.push_back(Arg); + } + return make<EnclosingExpr>( + "sizeof... (", make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)), + ")"); + } } return nullptr; case 't': @@ -4836,6 +5040,22 @@ Node *Db::parse() { return nullptr; return Ty; } + +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 true; + BufferSize = InitSize; + } else + BufferSize = *N; + + S.reset(Buf, BufferSize); + return false; +} + } // unnamed namespace enum { @@ -4855,33 +5075,23 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { return nullptr; } - size_t BufSize = Buf != nullptr ? *N : 0; int InternalStatus = success; - size_t MangledNameLength = std::strlen(MangledName); + Db Parser(MangledName, MangledName + std::strlen(MangledName)); + OutputStream S; - Db Parser(MangledName, MangledName + MangledNameLength); Node *AST = Parser.parse(); if (AST == nullptr) InternalStatus = invalid_mangled_name; - - if (InternalStatus == success) { + else if (initializeOutputStream(Buf, N, S, 1024)) + InternalStatus = memory_alloc_failure; + else { assert(Parser.ForwardTemplateRefs.empty()); - - if (Buf == nullptr) { - BufSize = 1024; - Buf = static_cast<char*>(std::malloc(BufSize)); - } - - if (Buf) { - OutputStream Stream(Buf, BufSize); - AST->print(Stream); - Stream += '\0'; - if (N != nullptr) - *N = Stream.getCurrentPosition(); - Buf = Stream.getBuffer(); - } else - InternalStatus = memory_alloc_failure; + AST->print(S); + S += '\0'; + if (N != nullptr) + *N = S.getCurrentPosition(); + Buf = S.getBuffer(); } if (Status) diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp index b77f3a8..397427a 100644 --- a/src/cxa_exception.cpp +++ b/src/cxa_exception.cpp @@ -11,8 +11,6 @@ // //===----------------------------------------------------------------------===// -#define _LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS - #include "cxxabi.h" #include <exception> // for std::terminate @@ -20,6 +18,7 @@ #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); @@ -618,7 +617,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - __sync_add_and_fetch(&exception_header->referenceCount, 1); + std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); } } @@ -630,12 +629,12 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ -void -__cxa_decrement_exception_refcount(void *thrown_object) throw() { +_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 (__sync_sub_and_fetch(&exception_header->referenceCount, size_t(1)) == 0) + if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) { if (NULL != exception_header->exceptionDestructor) exception_header->exceptionDestructor(thrown_object); diff --git a/src/cxa_handlers.cpp b/src/cxa_handlers.cpp index 2881a2a..622e93c 100644 --- a/src/cxa_handlers.cpp +++ b/src/cxa_handlers.cpp @@ -18,6 +18,7 @@ #include "cxa_handlers.hpp" #include "cxa_exception.hpp" #include "private_typeinfo.h" +#include "include/atomic_support.h" namespace std { @@ -25,10 +26,7 @@ namespace std unexpected_handler get_unexpected() _NOEXCEPT { - return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0); -// The above is safe but overkill on x86 -// Using of C++11 atomics this should be rewritten -// return __cxa_unexpected_handler.load(memory_order_acq); + return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire); } void @@ -49,10 +47,7 @@ unexpected() terminate_handler get_terminate() _NOEXCEPT { - return __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0); -// The above is safe but overkill on x86 -// Using of C++11 atomics this should be rewritten -// return __cxa_terminate_handler.load(memory_order_acq); + return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire); } void @@ -99,8 +94,6 @@ terminate() _NOEXCEPT __terminate(get_terminate()); } -// In the future this will become: -// std::atomic<std::new_handler> __cxa_new_handler(0); extern "C" { new_handler __cxa_new_handler = 0; } @@ -108,18 +101,13 @@ new_handler __cxa_new_handler = 0; new_handler set_new_handler(new_handler handler) _NOEXCEPT { - return __atomic_exchange_n(&__cxa_new_handler, handler, __ATOMIC_ACQ_REL); -// Using of C++11 atomics this should be rewritten -// return __cxa_new_handler.exchange(handler, memory_order_acq_rel); + return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel); } new_handler get_new_handler() _NOEXCEPT { - return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0); -// The above is safe but overkill on x86 -// Using of C++11 atomics this should be rewritten -// return __cxa_new_handler.load(memory_order_acq); + return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire); } } // std diff --git a/src/include/atomic_support.h b/src/include/atomic_support.h new file mode 100644 index 0000000..96dbd2c --- /dev/null +++ b/src/include/atomic_support.h @@ -0,0 +1,181 @@ +//===----------------------------------------------------------------------===//// +// +// 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/src/include/refstring.h b/src/include/refstring.h index bc131ae..69f6747 100644 --- a/src/include/refstring.h +++ b/src/include/refstring.h @@ -22,6 +22,7 @@ #include <dlfcn.h> #include <mach-o/dyld.h> #endif +#include "atomic_support.h" _LIBCPP_BEGIN_NAMESPACE_STD @@ -87,7 +88,7 @@ __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT : __imp_(s.__imp_) { if (__uses_refcount()) - __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); + __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); } inline @@ -96,10 +97,10 @@ __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _ struct _Rep_base *old_rep = rep_from_data(__imp_); __imp_ = s.__imp_; if (__uses_refcount()) - __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1); + __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1); if (adjust_old_count) { - if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0) + if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0) { ::operator delete(old_rep); } @@ -111,7 +112,7 @@ inline __libcpp_refstring::~__libcpp_refstring() { if (__uses_refcount()) { _Rep_base* rep = rep_from_data(__imp_); - if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0) { + if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) { ::operator delete(rep); } } diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp index ef9466e..a0326a1 100644 --- a/src/private_typeinfo.cpp +++ b/src/private_typeinfo.cpp @@ -859,13 +859,14 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, // 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; - bool does_dst_type_point_to_our_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). @@ -909,21 +910,6 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, } } } - 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; - } // 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 @@ -932,7 +918,22 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, 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 @@ -1030,13 +1031,13 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info, // 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; - bool does_dst_type_point_to_our_static_type = false; // Zero out found flags info->found_our_static_ptr = false; info->found_any_static_type = false; @@ -1047,20 +1048,6 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info, if (info->found_our_static_ptr) does_dst_type_point_to_our_static_type = true; } - 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; - } // 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 @@ -1070,6 +1057,20 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info, 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 @@ -1181,6 +1182,8 @@ __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, 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 @@ -1210,6 +1213,8 @@ __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, 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 diff --git a/test/dynamic_cast.pass.cpp b/test/dynamic_cast.pass.cpp new file mode 100644 index 0000000..5288f7c --- /dev/null +++ b/test/dynamic_cast.pass.cpp @@ -0,0 +1,154 @@ +//===------------------------- dynamic_cast.pass.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 <cassert> + +// This test explicitly tests dynamic cast with types that have inaccessible +// bases. +#if defined(__clang__) +#pragma clang diagnostic ignored "-Winaccessible-base" +#endif + +typedef char Pad1[43981]; +typedef char Pad2[34981]; +typedef char Pad3[93481]; +typedef char Pad4[13489]; +typedef char Pad5[81349]; +typedef char Pad6[34819]; +typedef char Pad7[3489]; + +namespace t1 +{ + +// PR33425 +struct C3 { virtual ~C3() {} Pad1 _; }; +struct C5 : protected virtual C3 { Pad2 _; }; +struct C6 : virtual C5 { Pad3 _; }; +struct C7 : virtual C3 { Pad4 _; }; +struct C9 : C6, C7 { Pad5 _; }; + +C9 c9; +C3 *c3 = &c9; + +void test() +{ + assert(dynamic_cast<C3*>(c3) == static_cast<C3*>(&c9)); + assert(dynamic_cast<C5*>(c3) == static_cast<C5*>(&c9)); + assert(dynamic_cast<C6*>(c3) == static_cast<C6*>(&c9)); + assert(dynamic_cast<C7*>(c3) == static_cast<C7*>(&c9)); + assert(dynamic_cast<C9*>(c3) == static_cast<C9*>(&c9)); +} + +} // t1 + +namespace t2 +{ + +// PR33425 +struct Src { virtual ~Src() {} Pad1 _; }; +struct Mask : protected virtual Src { Pad2 _; }; +struct Dest : Mask { Pad3 _; }; +struct Root : Dest, virtual Src { Pad4 _; }; + +Root root; +Src *src = &root; + +void test() +{ + assert(dynamic_cast<Src*>(src) == static_cast<Src*>(&root)); + assert(dynamic_cast<Mask*>(src) == static_cast<Mask*>(&root)); + assert(dynamic_cast<Dest*>(src) == static_cast<Dest*>(&root)); + assert(dynamic_cast<Root*>(src) == static_cast<Root*>(&root)); +} + +} // t2 + +namespace t3 +{ + +// PR33487 +struct Class1 { virtual ~Class1() {} Pad1 _; }; +struct Shared : virtual Class1 { Pad2 _; }; +struct Class6 : virtual Shared { Pad3 _; }; +struct Left : Class6 { Pad4 _; }; +struct Right : Class6 { Pad5 _; }; +struct Main : Left, Right { Pad6 _; }; + +Main m; +Class1 *c1 = &m; + +void test() +{ + assert(dynamic_cast<Class1*>(c1) == static_cast<Class1*>(&m)); + assert(dynamic_cast<Shared*>(c1) == static_cast<Shared*>(&m)); + assert(dynamic_cast<Class6*>(c1) == 0); + assert(dynamic_cast<Left*>(c1) == static_cast<Left*>(&m)); + assert(dynamic_cast<Right*>(c1) == static_cast<Right*>(&m)); + assert(dynamic_cast<Main*>(c1) == static_cast<Main*>(&m)); +} + +} // t3 + +namespace t4 +{ + +// PR33439 +struct C2 { virtual ~C2() {} Pad1 _; }; +struct C3 { virtual ~C3() {} Pad2 _; }; +struct C4 : C3 { Pad3 _; }; +struct C8 : C2, virtual C4 { Pad4 _; }; +struct C9 : C4, C8 { Pad5 _; }; + +C9 c9; +C2 *c2 = &c9; + +void test() +{ + assert(dynamic_cast<C2*>(c2) == static_cast<C2*>(&c9)); + assert(dynamic_cast<C3*>(c2) == 0); + assert(dynamic_cast<C4*>(c2) == 0); + assert(dynamic_cast<C8*>(c2) == static_cast<C8*>(&c9)); + assert(dynamic_cast<C9*>(c2) == static_cast<C9*>(&c9)); +} + +} // t4 + +namespace t5 +{ + +// PR33439 +struct Dummy { virtual ~Dummy() {} Pad1 _; }; +struct Src { virtual ~Src() {} Pad2 _; }; +struct Dest : Dummy { Pad3 _; }; +struct A1 : Dest { Pad4 _; }; +struct A2 : Dest { Pad5 _; }; +struct Root : Src, A1, A2 { Pad6 _; }; + +Root root; +Src *src = &root; + +void test() +{ + assert(dynamic_cast<Dummy*>(src) == 0); + assert(dynamic_cast<Src*>(src) == static_cast<Src*>(&root)); + assert(dynamic_cast<Dest*>(src) == 0); + assert(dynamic_cast<A1*>(src) == static_cast<A1*>(&root)); + assert(dynamic_cast<A2*>(src) == static_cast<A2*>(&root)); +} + +} // t5 + +int main() +{ + t1::test(); + t2::test(); + t3::test(); + t4::test(); + t5::test(); +} diff --git a/test/libcxxabi/test/config.py b/test/libcxxabi/test/config.py index d24fc5b..f294c8b 100644 --- a/test/libcxxabi/test/config.py +++ b/test/libcxxabi/test/config.py @@ -49,7 +49,10 @@ class Configuration(LibcxxConfiguration): self.config.available_features.add('libcxxabi-has-system-unwinder') def configure_compile_flags(self): - self.cxx.compile_flags += ['-DLIBCXXABI_NO_TIMER'] + self.cxx.compile_flags += [ + '-DLIBCXXABI_NO_TIMER', + '-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS', + ] if self.get_lit_bool('enable_exceptions', True): self.cxx.compile_flags += ['-funwind-tables'] else: diff --git a/test/test_demangle.pass.cpp b/test/test_demangle.pass.cpp index 98921c2..ea7a0fa 100644 --- a/test/test_demangle.pass.cpp +++ b/test/test_demangle.pass.cpp @@ -29738,6 +29738,17 @@ const char* cases[][2] = {"_ZN5OuterI4MarpEcvT_I4MerpEEv", "Outer<Marp>::operator Merp<Merp>()"}, {"_ZZN5OuterI4MarpEcv7MuncherIJT_T0_DpT1_EEI4MerpS0_JicfEEEvEN1ScvS9_Ev", "Outer<Marp>::operator Muncher<Merp, Marp, int, char, float><Merp, Marp, int, char, float>()::S::operator Merp()"}, {"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv", "S::operator Muncher<int (*)(), int (*) []><int (), int []>()"}, + + {"_Z2f8IiJ8identityIiES0_IfEEEvRAsPiDpT0_T_DpNS3_4typeEE_i", "void f8<int, identity<int>, identity<float> >(int (&) [sizeof... (int, identity<int>, identity<float>, int, identity<int>::type, identity<float>::type)])"}, + + {"_ZNK13StaticMembersIfE1xMUlvE_clEv", "StaticMembers<float>::x::'lambda'()::operator()() const"}, + {"_ZNK10inline_varMUlvE_clEv", "inline_var::'lambda'()::operator()() const"}, + // C++1z fold expressions: + {"_Z6foldl1IJLi1ELi2ELi3EEEv1AIXfLplLi1ET_EE", "void foldl1<1, 2, 3>(A<(1 + ... + (1, 2, 3))>)"}, + {"_Z6foldr1IJLi1ELi2ELi3EEEv1AIXfRplT_Li1EEE", "void foldr1<1, 2, 3>(A<((1, 2, 3) + ... + 1)>)"}, + {"_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) + ...))))))>)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); diff --git a/test/test_exception_storage.pass.cpp b/test/test_exception_storage.pass.cpp index 49c9b5d..ef2524f 100644 --- a/test/test_exception_storage.pass.cpp +++ b/test/test_exception_storage.pass.cpp @@ -7,11 +7,6 @@ // //===----------------------------------------------------------------------===// -// FIXME: cxa_exception.hpp directly references `std::unexpected` and friends. -// This breaks this test when compiled in C++17. For now fix this by manually -// re-enabling the STL functions. -#define _LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS - #include <cstdlib> #include <algorithm> #include <iostream> |