aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.ru>2022-06-01 06:53:46 +0300
committerthegeorg <thegeorg@yandex-team.ru>2022-06-01 06:53:46 +0300
commit85b999d095a6eb42b26cfa08ea161c040da10d27 (patch)
tree3562eee33a7e59ef87ada6615d11a42f554c1afd
parent69303758972378040a4f042a3fa82e3bb8450390 (diff)
downloadydb-85b999d095a6eb42b26cfa08ea161c040da10d27.tar.gz
Update contrib/libs/cxxsupp/libcxxabi to 14.0.4
ref:9027119e143437bfa6df5c013a9b754905669a23
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h321
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h127
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/README.txt71
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/StringView.h17
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h14
5 files changed, 343 insertions, 207 deletions
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h b/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
index df3f4a48bb..5a7cbfd5cd 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
@@ -23,9 +23,15 @@
* the thread currently performing initialization is stored in the second word.
*
* Guard Object Layout:
- * -------------------------------------------------------------------------
- * |a: guard byte | a+1: init byte | a+2 : unused ... | a+4: thread-id ... |
- * -------------------------------------------------------------------------
+ * ---------------------------------------------------------------------------
+ * | a+0: guard byte | a+1: init byte | a+2: unused ... | a+4: thread-id ... |
+ * ---------------------------------------------------------------------------
+ *
+ * Note that we don't do what the ABI docs suggest (put a mutex in the guard
+ * object which we acquire in cxa_guard_acquire and release in
+ * cxa_guard_release). Instead we use the init byte to imitate that behaviour,
+ * but without actually holding anything mutex related between aquire and
+ * release/abort.
*
* Access Protocol:
* For each implementation the guard byte is checked and set before accessing
@@ -48,6 +54,7 @@
# endif
#endif
+#include <limits.h>
#include <stdlib.h>
#include <__threading_support>
#ifndef _LIBCXXABI_HAS_NO_THREADS
@@ -156,92 +163,107 @@ uint32_t PlatformThreadID() {
constexpr uint32_t (*PlatformThreadID)() = nullptr;
#endif
-constexpr bool PlatformSupportsThreadID() { return +PlatformThreadID != nullptr; }
-
//===----------------------------------------------------------------------===//
-// GuardBase
+// GuardByte
//===----------------------------------------------------------------------===//
-enum class AcquireResult {
- INIT_IS_DONE,
- INIT_IS_PENDING,
-};
-constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
-constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
-
static constexpr uint8_t UNSET = 0;
static constexpr uint8_t COMPLETE_BIT = (1 << 0);
static constexpr uint8_t PENDING_BIT = (1 << 1);
static constexpr uint8_t WAITING_BIT = (1 << 2);
-template <class Derived>
-struct GuardObject {
- GuardObject() = delete;
- GuardObject(GuardObject const&) = delete;
- GuardObject& operator=(GuardObject const&) = delete;
-
- explicit GuardObject(uint32_t* g)
- : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
- init_byte_address(reinterpret_cast<uint8_t*>(g) + 1), thread_id_address(nullptr) {}
+/// Manages reads and writes to the guard byte.
+struct GuardByte {
+ GuardByte() = delete;
+ GuardByte(GuardByte const&) = delete;
+ GuardByte& operator=(GuardByte const&) = delete;
- explicit GuardObject(uint64_t* g)
- : base_address(g), guard_byte_address(reinterpret_cast<uint8_t*>(g)),
- init_byte_address(reinterpret_cast<uint8_t*>(g) + 1), thread_id_address(reinterpret_cast<uint32_t*>(g) + 1) {}
+ explicit GuardByte(uint8_t* const guard_byte_address) : guard_byte(guard_byte_address) {}
public:
- /// Implements __cxa_guard_acquire
- AcquireResult cxa_guard_acquire() {
- AtomicInt<uint8_t> guard_byte(guard_byte_address);
- if (guard_byte.load(std::_AO_Acquire) != UNSET)
- return INIT_IS_DONE;
- return derived()->acquire_init_byte();
- }
-
- /// Implements __cxa_guard_release
- void cxa_guard_release() {
- AtomicInt<uint8_t> guard_byte(guard_byte_address);
- // Store complete first, so that when release wakes other folks, they see
- // it as having been completed.
- guard_byte.store(COMPLETE_BIT, std::_AO_Release);
- derived()->release_init_byte();
+ /// The guard byte portion of cxa_guard_acquire. Returns true if
+ /// initialization has already been completed.
+ bool acquire() {
+ // if guard_byte is non-zero, we have already completed initialization
+ // (i.e. release has been called)
+ return guard_byte.load(std::_AO_Acquire) != UNSET;
}
- /// Implements __cxa_guard_abort
- void cxa_guard_abort() { derived()->abort_init_byte(); }
+ /// The guard byte portion of cxa_guard_release.
+ void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); }
-public:
- /// base_address - the address of the original guard object.
- void* const base_address;
- /// The address of the guard byte at offset 0.
- uint8_t* const guard_byte_address;
- /// The address of the byte used by the implementation during initialization.
- uint8_t* const init_byte_address;
- /// An optional address storing an identifier for the thread performing initialization.
- /// It's used to detect recursive initialization.
- uint32_t* const thread_id_address;
+ /// The guard byte portion of cxa_guard_abort.
+ void abort() {} // Nothing to do
private:
- Derived* derived() { return static_cast<Derived*>(this); }
+ AtomicInt<uint8_t> guard_byte;
};
//===----------------------------------------------------------------------===//
+// InitByte Implementations
+//===----------------------------------------------------------------------===//
+//
+// Each initialization byte implementation supports the following methods:
+//
+// InitByte(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
+// Construct the InitByte object, initializing our member variables
+//
+// bool acquire()
+// Called before we start the initialization. Check if someone else has already started, and if
+// not to signal our intent to start it ourselves. We determine the current status from the init
+// byte, which is one of 4 possible values:
+// COMPLETE: Initialization was finished by somebody else. Return true.
+// PENDING: Somebody has started the initialization already, set the WAITING bit,
+// then wait for the init byte to get updated with a new value.
+// (PENDING|WAITING): Somebody has started the initialization already, and we're not the
+// first one waiting. Wait for the init byte to get updated.
+// UNSET: Initialization hasn't successfully completed, and nobody is currently
+// performing the initialization. Set the PENDING bit to indicate our
+// intention to start the initialization, and return false.
+// The return value indicates whether initialization has already been completed.
+//
+// void release()
+// Called after successfully completing the initialization. Update the init byte to reflect
+// that, then if anybody else is waiting, wake them up.
+//
+// void abort()
+// Called after an error is thrown during the initialization. Reset the init byte to UNSET to
+// indicate that we're no longer performing the initialization, then if anybody is waiting, wake
+// them up so they can try performing the initialization.
+//
+
+//===----------------------------------------------------------------------===//
// Single Threaded Implementation
//===----------------------------------------------------------------------===//
-struct InitByteNoThreads : GuardObject<InitByteNoThreads> {
- using GuardObject::GuardObject;
+/// InitByteNoThreads - Doesn't use any inter-thread synchronization when
+/// managing reads and writes to the init byte.
+struct InitByteNoThreads {
+ InitByteNoThreads() = delete;
+ InitByteNoThreads(InitByteNoThreads const&) = delete;
+ InitByteNoThreads& operator=(InitByteNoThreads const&) = delete;
- AcquireResult acquire_init_byte() {
+ explicit InitByteNoThreads(uint8_t* _init_byte_address, uint32_t*) : init_byte_address(_init_byte_address) {}
+
+ /// The init byte portion of cxa_guard_acquire. Returns true if
+ /// initialization has already been completed.
+ bool acquire() {
if (*init_byte_address == COMPLETE_BIT)
- return INIT_IS_DONE;
+ return true;
if (*init_byte_address & PENDING_BIT)
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
*init_byte_address = PENDING_BIT;
- return INIT_IS_PENDING;
+ return false;
}
- void release_init_byte() { *init_byte_address = COMPLETE_BIT; }
- void abort_init_byte() { *init_byte_address = UNSET; }
+ /// The init byte portion of cxa_guard_release.
+ void release() { *init_byte_address = COMPLETE_BIT; }
+ /// The init byte portion of cxa_guard_abort.
+ void abort() { *init_byte_address = UNSET; }
+
+private:
+ /// The address of the byte used during initialization.
+ uint8_t* const init_byte_address;
};
//===----------------------------------------------------------------------===//
@@ -281,18 +303,20 @@ struct LibcppMutex {};
struct LibcppCondVar {};
#endif // !defined(_LIBCXXABI_HAS_NO_THREADS)
+/// InitByteGlobalMutex - Uses a global mutex and condition variable (common to
+/// all static local variables) to manage reads and writes to the init byte.
template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
uint32_t (*GetThreadID)() = PlatformThreadID>
-struct InitByteGlobalMutex : GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond, GetThreadID>> {
+struct InitByteGlobalMutex {
- using BaseT = typename InitByteGlobalMutex::GuardObject;
- using BaseT::BaseT;
-
- explicit InitByteGlobalMutex(uint32_t* g) : BaseT(g), has_thread_id_support(false) {}
- explicit InitByteGlobalMutex(uint64_t* g) : BaseT(g), has_thread_id_support(PlatformSupportsThreadID()) {}
+ explicit InitByteGlobalMutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
+ : init_byte_address(_init_byte_address), thread_id_address(_thread_id_address),
+ has_thread_id_support(_thread_id_address != nullptr && GetThreadID != nullptr) {}
public:
- AcquireResult acquire_init_byte() {
+ /// The init byte portion of cxa_guard_acquire. Returns true if
+ /// initialization has already been completed.
+ bool acquire() {
LockGuard g("__cxa_guard_acquire");
// Check for possible recursive initialization.
if (has_thread_id_support && (*init_byte_address & PENDING_BIT)) {
@@ -307,16 +331,17 @@ public:
}
if (*init_byte_address == COMPLETE_BIT)
- return INIT_IS_DONE;
+ return true;
if (has_thread_id_support)
*thread_id_address = current_thread_id.get();
*init_byte_address = PENDING_BIT;
- return INIT_IS_PENDING;
+ return false;
}
- void release_init_byte() {
+ /// The init byte portion of cxa_guard_release.
+ void release() {
bool has_waiting;
{
LockGuard g("__cxa_guard_release");
@@ -330,7 +355,8 @@ public:
}
}
- void abort_init_byte() {
+ /// The init byte portion of cxa_guard_abort.
+ void abort() {
bool has_waiting;
{
LockGuard g("__cxa_guard_abort");
@@ -347,8 +373,12 @@ public:
}
private:
- using BaseT::init_byte_address;
- using BaseT::thread_id_address;
+ /// The address of the byte used during initialization.
+ uint8_t* const init_byte_address;
+ /// An optional address storing an identifier for the thread performing initialization.
+ /// It's used to detect recursive initialization.
+ uint32_t* const thread_id_address;
+
const bool has_thread_id_support;
LazyValue<uint32_t, GetThreadID> current_thread_id;
@@ -395,36 +425,32 @@ constexpr void (*PlatformFutexWake)(int*) = nullptr;
constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; }
-/// InitByteFutex - Manages initialization using atomics and the futex syscall
-/// for waiting and waking.
+/// InitByteFutex - Uses a futex to manage reads and writes to the init byte.
template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
uint32_t (*GetThreadIDArg)() = PlatformThreadID>
-struct InitByteFutex : GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>> {
- using BaseT = typename InitByteFutex::GuardObject;
-
- /// ARM Constructor
- explicit InitByteFutex(uint32_t* g)
- : BaseT(g), init_byte(this->init_byte_address), has_thread_id_support(this->thread_id_address && GetThreadIDArg),
- thread_id(this->thread_id_address) {}
+struct InitByteFutex {
- /// Itanium Constructor
- explicit InitByteFutex(uint64_t* g)
- : BaseT(g), init_byte(this->init_byte_address), has_thread_id_support(this->thread_id_address && GetThreadIDArg),
- thread_id(this->thread_id_address) {}
+ explicit InitByteFutex(uint8_t* _init_byte_address, uint32_t* _thread_id_address)
+ : init_byte(_init_byte_address),
+ has_thread_id_support(_thread_id_address != nullptr && GetThreadIDArg != nullptr),
+ thread_id(_thread_id_address),
+ base_address(reinterpret_cast<int*>(/*_init_byte_address & ~0x3*/ _init_byte_address - 1)) {}
public:
- AcquireResult acquire_init_byte() {
+ /// The init byte portion of cxa_guard_acquire. Returns true if
+ /// initialization has already been completed.
+ bool acquire() {
while (true) {
uint8_t last_val = UNSET;
if (init_byte.compare_exchange(&last_val, PENDING_BIT, std::_AO_Acq_Rel, std::_AO_Acquire)) {
if (has_thread_id_support) {
thread_id.store(current_thread_id.get(), std::_AO_Relaxed);
}
- return INIT_IS_PENDING;
+ return false;
}
if (last_val == COMPLETE_BIT)
- return INIT_IS_DONE;
+ return true;
if (last_val & PENDING_BIT) {
@@ -441,7 +467,7 @@ public:
if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT, std::_AO_Acq_Rel, std::_AO_Release)) {
// (1) success, via someone else's work!
if (last_val == COMPLETE_BIT)
- return INIT_IS_DONE;
+ return true;
// (3) someone else, bailed on doing the work, retry from the start!
if (last_val == UNSET)
@@ -455,13 +481,15 @@ public:
}
}
- void release_init_byte() {
+ /// The init byte portion of cxa_guard_release.
+ void release() {
uint8_t old = init_byte.exchange(COMPLETE_BIT, std::_AO_Acq_Rel);
if (old & WAITING_BIT)
wake_all();
}
- void abort_init_byte() {
+ /// The init byte portion of cxa_guard_abort.
+ void abort() {
if (has_thread_id_support)
thread_id.store(0, std::_AO_Relaxed);
@@ -472,12 +500,11 @@ public:
private:
/// Use the futex to wait on the current guard variable. Futex expects a
- /// 32-bit 4-byte aligned address as the first argument, so we have to use use
- /// the base address of the guard variable (not the init byte).
- void wait_on_initialization() {
- Wait(static_cast<int*>(this->base_address), expected_value_for_futex(PENDING_BIT | WAITING_BIT));
- }
- void wake_all() { Wake(static_cast<int*>(this->base_address)); }
+ /// 32-bit 4-byte aligned address as the first argument, so we use the 4-byte
+ /// aligned address that encompasses the init byte (i.e. the address of the
+ /// raw guard object that was passed to __cxa_guard_acquire/release/abort).
+ void wait_on_initialization() { Wait(base_address, expected_value_for_futex(PENDING_BIT | WAITING_BIT)); }
+ void wake_all() { Wake(base_address); }
private:
AtomicInt<uint8_t> init_byte;
@@ -487,6 +514,10 @@ private:
AtomicInt<uint32_t> thread_id;
LazyValue<uint32_t, GetThreadIDArg> current_thread_id;
+ /// the 4-byte-aligned address that encompasses the init byte (i.e. the
+ /// address of the raw guard object).
+ int* const base_address;
+
/// Create the expected integer value for futex `wait(int* addr, int expected)`.
/// We pass the base address as the first argument, So this function creates
/// an zero-initialized integer with `b` copied at the correct offset.
@@ -500,6 +531,86 @@ private:
};
//===----------------------------------------------------------------------===//
+// GuardObject
+//===----------------------------------------------------------------------===//
+
+enum class AcquireResult {
+ INIT_IS_DONE,
+ INIT_IS_PENDING,
+};
+constexpr AcquireResult INIT_IS_DONE = AcquireResult::INIT_IS_DONE;
+constexpr AcquireResult INIT_IS_PENDING = AcquireResult::INIT_IS_PENDING;
+
+/// Co-ordinates between GuardByte and InitByte.
+template <class InitByteT>
+struct GuardObject {
+ GuardObject() = delete;
+ GuardObject(GuardObject const&) = delete;
+ GuardObject& operator=(GuardObject const&) = delete;
+
+private:
+ GuardByte guard_byte;
+ InitByteT init_byte;
+
+public:
+ /// ARM Constructor
+ explicit GuardObject(uint32_t* raw_guard_object)
+ : guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
+ init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, nullptr) {}
+
+ /// Itanium Constructor
+ explicit GuardObject(uint64_t* raw_guard_object)
+ : guard_byte(reinterpret_cast<uint8_t*>(raw_guard_object)),
+ init_byte(reinterpret_cast<uint8_t*>(raw_guard_object) + 1, reinterpret_cast<uint32_t*>(raw_guard_object) + 1) {
+ }
+
+ /// Implements __cxa_guard_acquire.
+ AcquireResult cxa_guard_acquire() {
+ // Use short-circuit evaluation to avoid calling init_byte.acquire when
+ // guard_byte.acquire returns true. (i.e. don't call it when we know from
+ // the guard byte that initialization has already been completed)
+ if (guard_byte.acquire() || init_byte.acquire())
+ return INIT_IS_DONE;
+ return INIT_IS_PENDING;
+ }
+
+ /// Implements __cxa_guard_release.
+ void cxa_guard_release() {
+ // Update guard byte first, so if somebody is woken up by init_byte.release
+ // and comes all the way back around to __cxa_guard_acquire again, they see
+ // it as having completed initialization.
+ guard_byte.release();
+ init_byte.release();
+ }
+
+ /// Implements __cxa_guard_abort.
+ void cxa_guard_abort() {
+ guard_byte.abort();
+ init_byte.abort();
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Convenience Classes
+//===----------------------------------------------------------------------===//
+
+/// NoThreadsGuard - Manages initialization without performing any inter-thread
+/// synchronization.
+using NoThreadsGuard = GuardObject<InitByteNoThreads>;
+
+/// GlobalMutexGuard - Manages initialization using a global mutex and
+/// condition variable.
+template <class Mutex, class CondVar, Mutex& global_mutex, CondVar& global_cond,
+ uint32_t (*GetThreadID)() = PlatformThreadID>
+using GlobalMutexGuard = GuardObject<InitByteGlobalMutex<Mutex, CondVar, global_mutex, global_cond, GetThreadID>>;
+
+/// FutexGuard - Manages initialization using atomics and the futex syscall for
+/// waiting and waking.
+template <void (*Wait)(int*, int) = PlatformFutexWait, void (*Wake)(int*) = PlatformFutexWake,
+ uint32_t (*GetThreadIDArg)() = PlatformThreadID>
+using FutexGuard = GuardObject<InitByteFutex<Wait, Wake, GetThreadIDArg>>;
+
+//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
@@ -510,25 +621,25 @@ struct GlobalStatic {
template <class T>
_LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
-enum class Implementation { NoThreads, GlobalLock, Futex };
+enum class Implementation { NoThreads, GlobalMutex, Futex };
template <Implementation Impl>
struct SelectImplementation;
template <>
struct SelectImplementation<Implementation::NoThreads> {
- using type = InitByteNoThreads;
+ using type = NoThreadsGuard;
};
template <>
-struct SelectImplementation<Implementation::GlobalLock> {
- using type = InitByteGlobalMutex<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
- GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
+struct SelectImplementation<Implementation::GlobalMutex> {
+ using type = GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
+ GlobalStatic<LibcppCondVar>::instance, PlatformThreadID>;
};
template <>
struct SelectImplementation<Implementation::Futex> {
- using type = InitByteFutex<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
+ using type = FutexGuard<PlatformFutexWait, PlatformFutexWake, PlatformThreadID>;
};
// TODO(EricWF): We should prefer the futex implementation when available. But
@@ -539,7 +650,7 @@ constexpr Implementation CurrentImplementation =
#elif defined(_LIBCXXABI_USE_FUTEX)
Implementation::Futex;
#else
- Implementation::GlobalLock;
+ Implementation::GlobalMutex;
#endif
static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(),
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
index 85e1511346..db65c60e7e 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -6,8 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
-// Generic itanium demangler library. This file has two byte-per-byte identical
-// copies in the source tree, one in libcxxabi, and the other in llvm.
+// Generic itanium demangler library.
+// There are two copies of this file in the source tree. The one under
+// libcxxabi is the original and the one under llvm is the copy. Use
+// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
@@ -21,12 +23,13 @@
#include "DemangleConfig.h"
#include "StringView.h"
#include "Utility.h"
+#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <numeric>
+#include <limits>
#include <utility>
#define FOR_EACH_NODE_KIND(X) \
@@ -310,7 +313,7 @@ public:
printRight(OB);
}
- // Print the "left" side of this Node into OutputString.
+ // Print the "left" side of this Node into OutputBuffer.
virtual void printLeft(OutputBuffer &) const = 0;
// Print the "right". This distinction is necessary to represent C++ types
@@ -1210,7 +1213,8 @@ public:
class ParameterPack final : public Node {
NodeArray Data;
- // Setup OutputString for a pack expansion unless we're already expanding one.
+ // Setup OutputBuffer for a pack expansion, unless we're already expanding
+ // one.
void initializePackExpansion(OutputBuffer &OB) const {
if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
OB.CurrentPackMax = static_cast<unsigned>(Data.size());
@@ -2473,7 +2477,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
char consume() { return First != Last ? *First++ : '\0'; }
- char look(unsigned Lookahead = 0) {
+ char look(unsigned Lookahead = 0) const {
if (static_cast<size_t>(Last - First) <= Lookahead)
return '\0';
return First[Lookahead];
@@ -2591,34 +2595,38 @@ Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *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 *Result = nullptr;
+ bool IsSubst = look() == 'S' && look(1) != 't';
+ if (IsSubst) {
+ // A substitution must lead to:
+ // ::= <unscoped-template-name> <template-args>
+ Result = getDerived().parseSubstitution();
+ } else {
+ // An unscoped name can be one of:
+ // ::= <unscoped-name>
+ // ::= <unscoped-template-name> <template-args>
+ Result = getDerived().parseUnscopedName(State);
}
-
- Node *N = getDerived().parseUnscopedName(State);
- if (N == nullptr)
+ if (Result == nullptr)
return nullptr;
- // ::= <unscoped-template-name> <template-args>
+
if (look() == 'I') {
- Subs.push_back(N);
+ // ::= <unscoped-template-name> <template-args>
+ if (!IsSubst)
+ // An unscoped-template-name is substitutable.
+ Subs.push_back(Result);
Node *TA = getDerived().parseTemplateArgs(State != nullptr);
if (TA == nullptr)
return nullptr;
- if (State) State->EndsWithTemplateArgs = true;
- return make<NameWithTemplateArgs>(N, TA);
+ if (State)
+ State->EndsWithTemplateArgs = true;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else if (IsSubst) {
+ // The substitution case must be followed by <template-args>.
+ return nullptr;
}
- // ::= <unscoped-name>
- return N;
+
+ return Result;
}
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
@@ -2663,13 +2671,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
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);
+ bool IsStd = consumeIf("St");
+ if (IsStd)
+ consumeIf('L');
+
+ Node *Result = getDerived().parseUnqualifiedName(State);
+ if (Result == nullptr)
+ return nullptr;
+ if (IsStd)
+ Result = make<StdQualifiedName>(Result);
+
+ return Result;
}
// <unqualified-name> ::= <operator-name> [abi-tags]
@@ -4064,9 +4076,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
}
// ::= <substitution> # See Compression below
case 'S': {
- if (look(1) && look(1) != 't') {
- Node *Sub = getDerived().parseSubstitution();
- if (Sub == nullptr)
+ if (look(1) != 't') {
+ Result = getDerived().parseSubstitution();
+ if (Result == nullptr)
return nullptr;
// Sub could be either of:
@@ -4083,13 +4095,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
Node *TA = getDerived().parseTemplateArgs();
if (TA == nullptr)
return nullptr;
- Result = make<NameWithTemplateArgs>(Sub, TA);
- break;
+ Result = make<NameWithTemplateArgs>(Result, TA);
+ } else {
+ // If all we parsed was a substitution, don't re-insert into the
+ // substitution table.
+ return Result;
}
-
- // If all we parsed was a substitution, don't re-insert into the
- // substitution table.
- return Sub;
+ break;
}
DEMANGLE_FALLTHROUGH;
}
@@ -5437,38 +5449,35 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
if (!consumeIf('S'))
return nullptr;
- if (std::islower(look())) {
- Node *SpecialSub;
+ if (look() >= 'a' && look() <= 'z') {
+ SpecialSubKind Kind;
switch (look()) {
case 'a':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
+ Kind = SpecialSubKind::allocator;
break;
case 'b':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
+ Kind = SpecialSubKind::basic_string;
break;
- case 's':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
+ case 'd':
+ Kind = SpecialSubKind::iostream;
break;
case 'i':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
+ Kind = SpecialSubKind::istream;
break;
case 'o':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
+ Kind = SpecialSubKind::ostream;
break;
- case 'd':
- ++First;
- SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
+ case 's':
+ Kind = SpecialSubKind::string;
break;
default:
return nullptr;
}
+ ++First;
+ auto *SpecialSub = make<SpecialSubstitution>(Kind);
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.
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/README.txt b/contrib/libs/cxxsupp/libcxxabi/src/demangle/README.txt
index 514ff6dd16..76470f61f9 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/README.txt
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/README.txt
@@ -4,41 +4,50 @@ Itanium Name Demangler Library
Introduction
------------
-This directory contains the generic itanium name demangler library. The main
-purpose of the library is to demangle C++ symbols, i.e. convert the string
-"_Z1fv" into "f()". You can also use the CRTP base ManglingParser to perform
-some simple analysis on the mangled name, or (in LLVM) use the opaque
-ItaniumPartialDemangler to query the demangled AST.
+This directory contains the generic itanium name demangler
+library. The main purpose of the library is to demangle C++ symbols,
+i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP
+base ManglingParser to perform some simple analysis on the mangled
+name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the
+demangled AST.
Why are there multiple copies of the this library in the source tree?
---------------------------------------------------------------------
-This directory is mirrored between libcxxabi/demangle and
-llvm/include/llvm/Demangle. The simple reason for this is that both projects
-need to demangle symbols, but neither can depend on each other. libcxxabi needs
-the demangler to implement __cxa_demangle, which is part of the itanium ABI
-spec. LLVM needs a copy for a bunch of places, but doesn't want to use the
-system's __cxa_demangle because it a) might not be available (i.e., on Windows),
-and b) probably isn't that up-to-date on the latest language features.
-
-The copy of the demangler in LLVM has some extra stuff that aren't needed in
-libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler), which depend on the
-shared generic components. Despite these differences, we want to keep the "core"
-generic demangling library identical between both copies to simplify development
-and testing.
-
-If you're working on the generic library, then do the work first in libcxxabi,
-then run the cp-to-llvm.sh script in src/demangle. This script takes as an
-argument the path to llvm, and re-copies the changes you made to libcxxabi over.
-Note that this script just blindly overwrites all changes to the generic library
-in llvm, so be careful.
-
-Because the core demangler needs to work in libcxxabi, everything needs to be
-declared in an anonymous namespace (see DEMANGLE_NAMESPACE_BEGIN), and you can't
-introduce any code that depends on the libcxx dylib.
-
-Hopefully, when LLVM becomes a monorepo, we can de-duplicate this code, and have
-both LLVM and libcxxabi depend on a shared demangler library.
+The canonical sources are in libcxxabi/src/demangle and some of the
+files are copied to llvm/include/llvm/Demangle. The simple reason for
+this comes from before the monorepo, and both [sub]projects need to
+demangle symbols, but neither can depend on each other.
+
+* libcxxabi needs the demangler to implement __cxa_demangle, which is
+ part of the itanium ABI spec.
+
+* LLVM needs a copy for a bunch of places, and cannot rely on the
+ system's __cxa_demangle because it a) might not be available (i.e.,
+ on Windows), and b) may not be up-to-date on the latest language
+ features.
+
+The copy of the demangler in LLVM has some extra stuff that aren't
+needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler),
+which depend on the shared generic components. Despite these
+differences, we want to keep the "core" generic demangling library
+identical between both copies to simplify development and testing.
+
+If you're working on the generic library, then do the work first in
+libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This
+script takes as an optional argument the path to llvm, and copies the
+changes you made to libcxxabi over. Note that this script just
+blindly overwrites all changes to the generic library in llvm, so be
+careful.
+
+Because the core demangler needs to work in libcxxabi, everything
+needs to be declared in an anonymous namespace (see
+DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that
+depends on the libcxx dylib.
+
+FIXME: Now that LLVM is a monorepo, it should be possible to
+de-duplicate this code, and have both LLVM and libcxxabi depend on a
+shared demangler library.
Testing
-------
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/StringView.h b/contrib/libs/cxxsupp/libcxxabi/src/demangle/StringView.h
index 1e4d3803f0..90890e3771 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/StringView.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/StringView.h
@@ -7,6 +7,9 @@
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
+// There are two copies of this file in the source tree. The one under
+// libcxxabi is the original and the one under llvm is the copy. Use
+// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
@@ -14,7 +17,6 @@
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
-#include <algorithm>
#include <cassert>
#include <cstring>
@@ -38,15 +40,16 @@ public:
StringView substr(size_t Pos, size_t Len = npos) const {
assert(Pos <= size());
- return StringView(begin() + Pos, std::min(Len, size() - Pos));
+ if (Len > size() - Pos)
+ Len = size() - Pos;
+ return StringView(begin() + Pos, Len);
}
size_t find(char C, size_t From = 0) const {
- size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
- if (FindBegin < size()) {
+ if (From < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
- if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
+ if (const void *P = ::memchr(First + From, C, size() - From))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
@@ -98,7 +101,7 @@ public:
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
- return std::equal(Str.begin(), Str.end(), begin());
+ return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@@ -111,7 +114,7 @@ public:
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
- std::equal(LHS.begin(), LHS.end(), RHS.begin());
+ std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
}
DEMANGLE_NAMESPACE_END
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h b/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
index 733d83ad1b..3b27328522 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
@@ -6,7 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
-// Provide some utility classes for use in the demangler(s).
+// Provide some utility classes for use in the demangler.
+// There are two copies of this file in the source tree. The one in libcxxabi
+// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
+// the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
@@ -14,10 +17,11 @@
#define DEMANGLE_UTILITY_H
#include "StringView.h"
+#include <array>
#include <cstdint>
#include <cstdlib>
#include <cstring>
-#include <iterator>
+#include <exception>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
@@ -48,8 +52,8 @@ class OutputBuffer {
return;
}
- char Temp[21];
- char *TempPtr = std::end(Temp);
+ std::array<char, 21> Temp;
+ char *TempPtr = Temp.data() + Temp.size();
while (N) {
*--TempPtr = char('0' + N % 10);
@@ -59,7 +63,7 @@ class OutputBuffer {
// Add negative sign...
if (isNeg)
*--TempPtr = '-';
- this->operator<<(StringView(TempPtr, std::end(Temp)));
+ this->operator<<(StringView(TempPtr, Temp.data() + Temp.size()));
}
public: