mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
update libcxxabi to llvm 14.0.6
This commit is contained in:
+2
-2
@@ -1,4 +1,4 @@
|
||||
//===-------------------------- __cxxabi_config.h -------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -93,7 +93,7 @@
|
||||
# if !__has_feature(cxx_exceptions)
|
||||
# define _LIBCXXABI_NO_EXCEPTIONS
|
||||
# endif
|
||||
#elif defined(_LIBCXXABI_COMPILER_GCC) && !__EXCEPTIONS
|
||||
#elif defined(_LIBCXXABI_COMPILER_GCC) && !defined(__EXCEPTIONS)
|
||||
# define _LIBCXXABI_NO_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===--------------------------- cxxabi.h ---------------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------- abort_message.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===-------------------------- abort_message.h-----------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------ cxa_aux_runtime.cpp -------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+13
-3
@@ -1,11 +1,12 @@
|
||||
//===------------------------- cxa_default_handlers.cpp -------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//
|
||||
// This file implements the default terminate_handler and unexpected_handler.
|
||||
// This file implements the default terminate_handler, unexpected_handler and
|
||||
// new_handler.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <exception>
|
||||
@@ -15,7 +16,7 @@
|
||||
#include "cxa_handlers.h"
|
||||
#include "cxa_exception.h"
|
||||
#include "private_typeinfo.h"
|
||||
#include "include/atomic_support.h"
|
||||
#include "include/atomic_support.h" // from libc++
|
||||
|
||||
#if !defined(LIBCXXABI_SILENT_TERMINATE)
|
||||
|
||||
@@ -104,6 +105,9 @@ _LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_ter
|
||||
_LIBCXXABI_DATA_VIS
|
||||
_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
|
||||
|
||||
_LIBCXXABI_DATA_VIS
|
||||
_LIBCPP_SAFE_STATIC std::new_handler __cxa_new_handler = 0;
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
@@ -125,4 +129,10 @@ set_terminate(terminate_handler func) noexcept
|
||||
_AO_Acq_Rel);
|
||||
}
|
||||
|
||||
new_handler
|
||||
set_new_handler(new_handler handler) noexcept
|
||||
{
|
||||
return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+7
-7
@@ -1,4 +1,4 @@
|
||||
//===-------------------------- cxa_demangle.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -342,21 +342,21 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
|
||||
|
||||
int InternalStatus = demangle_success;
|
||||
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
|
||||
OutputStream S;
|
||||
OutputBuffer O;
|
||||
|
||||
Node *AST = Parser.parse();
|
||||
|
||||
if (AST == nullptr)
|
||||
InternalStatus = demangle_invalid_mangled_name;
|
||||
else if (!initializeOutputStream(Buf, N, S, 1024))
|
||||
else if (!initializeOutputBuffer(Buf, N, O, 1024))
|
||||
InternalStatus = demangle_memory_alloc_failure;
|
||||
else {
|
||||
assert(Parser.ForwardTemplateRefs.empty());
|
||||
AST->print(S);
|
||||
S += '\0';
|
||||
AST->print(O);
|
||||
O += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
Buf = S.getBuffer();
|
||||
*N = O.getCurrentPosition();
|
||||
Buf = O.getBuffer();
|
||||
}
|
||||
|
||||
if (Status)
|
||||
|
||||
Vendored
+19
-11
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_exception.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "cxa_exception.h"
|
||||
#include "cxa_handlers.h"
|
||||
#include "fallback_malloc.h"
|
||||
#include "include/atomic_support.h"
|
||||
#include "include/atomic_support.h" // from libc++
|
||||
|
||||
#if __has_feature(address_sanitizer)
|
||||
#include <sanitizer/asan_interface.h>
|
||||
@@ -341,8 +341,10 @@ unwinding with _Unwind_Resume.
|
||||
According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
|
||||
register, thus we have to write this function in assembly so that we can save
|
||||
{r1, r2, r3}. We don't have to save r0 because it is the return value and the
|
||||
first argument to _Unwind_Resume(). In addition, we are saving r4 in order to
|
||||
align the stack to 16 bytes, even though it is a callee-save register.
|
||||
first argument to _Unwind_Resume(). In addition, we are saving lr in order to
|
||||
align the stack to 16 bytes and lr will be used to identify the caller and its
|
||||
frame information. _Unwind_Resume never return and we need to keep the original
|
||||
lr so just branch to it.
|
||||
*/
|
||||
__attribute__((used)) static _Unwind_Exception *
|
||||
__cxa_end_cleanup_impl()
|
||||
@@ -372,18 +374,24 @@ __cxa_end_cleanup_impl()
|
||||
return &exception_header->unwindHeader;
|
||||
}
|
||||
|
||||
asm (
|
||||
" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
|
||||
asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
|
||||
" .globl __cxa_end_cleanup\n"
|
||||
" .type __cxa_end_cleanup,%function\n"
|
||||
"__cxa_end_cleanup:\n"
|
||||
" push {r1, r2, r3, r4}\n"
|
||||
#if defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
" bti\n"
|
||||
#endif
|
||||
" push {r1, r2, r3, lr}\n"
|
||||
" bl __cxa_end_cleanup_impl\n"
|
||||
" pop {r1, r2, r3, r4}\n"
|
||||
" bl _Unwind_Resume\n"
|
||||
" bl abort\n"
|
||||
" .popsection"
|
||||
);
|
||||
" mov lr, r4\n"
|
||||
#if defined(LIBCXXABI_BAREMETAL)
|
||||
" ldr r4, =_Unwind_Resume\n"
|
||||
" bx r4\n"
|
||||
#else
|
||||
" b _Unwind_Resume\n"
|
||||
#endif
|
||||
" .popsection");
|
||||
#endif // defined(_LIBCXXABI_ARM_EHABI)
|
||||
|
||||
/*
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_exception.h ----------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+33
-35
@@ -1,4 +1,4 @@
|
||||
//===--------------------- cxa_exception_storage.cpp ----------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -21,25 +21,24 @@ extern "C" {
|
||||
static __cxa_eh_globals eh_globals;
|
||||
__cxa_eh_globals *__cxa_get_globals() { return &eh_globals; }
|
||||
__cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; }
|
||||
}
|
||||
}
|
||||
} // extern "C"
|
||||
} // namespace __cxxabiv1
|
||||
|
||||
#elif defined(HAS_THREAD_LOCAL)
|
||||
|
||||
namespace __cxxabiv1 {
|
||||
|
||||
namespace {
|
||||
__cxa_eh_globals * __globals () {
|
||||
__cxa_eh_globals *__globals() {
|
||||
static thread_local __cxa_eh_globals eh_globals;
|
||||
return &eh_globals;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
__cxa_eh_globals * __cxa_get_globals () { return __globals (); }
|
||||
__cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); }
|
||||
}
|
||||
}
|
||||
__cxa_eh_globals *__cxa_get_globals() { return __globals(); }
|
||||
__cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); }
|
||||
} // extern "C"
|
||||
} // namespace __cxxabiv1
|
||||
|
||||
#else
|
||||
|
||||
@@ -59,47 +58,46 @@ namespace {
|
||||
std::__libcpp_tls_key key_;
|
||||
std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER;
|
||||
|
||||
void _LIBCPP_TLS_DESTRUCTOR_CC destruct_ (void *p) {
|
||||
__free_with_fallback ( p );
|
||||
if ( 0 != std::__libcpp_tls_set ( key_, NULL ) )
|
||||
void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) {
|
||||
__free_with_fallback(p);
|
||||
if (0 != std::__libcpp_tls_set(key_, NULL))
|
||||
abort_message("cannot zero out thread value for __cxa_get_globals()");
|
||||
}
|
||||
}
|
||||
|
||||
void construct_ () {
|
||||
if ( 0 != std::__libcpp_tls_create ( &key_, destruct_ ) )
|
||||
void construct_() {
|
||||
if (0 != std::__libcpp_tls_create(&key_, destruct_))
|
||||
abort_message("cannot create thread specific key for __cxa_get_globals()");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
__cxa_eh_globals * __cxa_get_globals () {
|
||||
// Try to get the globals for this thread
|
||||
__cxa_eh_globals* retVal = __cxa_get_globals_fast ();
|
||||
__cxa_eh_globals *__cxa_get_globals() {
|
||||
// Try to get the globals for this thread
|
||||
__cxa_eh_globals *retVal = __cxa_get_globals_fast();
|
||||
|
||||
// If this is the first time we've been asked for these globals, create them
|
||||
if ( NULL == retVal ) {
|
||||
retVal = static_cast<__cxa_eh_globals*>
|
||||
(__calloc_with_fallback (1, sizeof (__cxa_eh_globals)));
|
||||
if ( NULL == retVal )
|
||||
// If this is the first time we've been asked for these globals, create them
|
||||
if (NULL == retVal) {
|
||||
retVal = static_cast<__cxa_eh_globals*>(
|
||||
__calloc_with_fallback(1, sizeof(__cxa_eh_globals)));
|
||||
if (NULL == retVal)
|
||||
abort_message("cannot allocate __cxa_eh_globals");
|
||||
if ( 0 != std::__libcpp_tls_set ( key_, retVal ) )
|
||||
if (0 != std::__libcpp_tls_set(key_, retVal))
|
||||
abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()");
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// Note that this implementation will reliably return NULL if not
|
||||
// preceded by a call to __cxa_get_globals(). This is an extension
|
||||
// to the Itanium ABI and is taken advantage of in several places in
|
||||
// libc++abi.
|
||||
__cxa_eh_globals * __cxa_get_globals_fast () {
|
||||
// First time through, create the key.
|
||||
__cxa_eh_globals *__cxa_get_globals_fast() {
|
||||
// First time through, create the key.
|
||||
if (0 != std::__libcpp_execute_once(&flag_, construct_))
|
||||
abort_message("execute once failure in __cxa_get_globals_fast()");
|
||||
// static int init = construct_();
|
||||
return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_));
|
||||
}
|
||||
}
|
||||
} // extern "C"
|
||||
} // namespace __cxxabiv1
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===---------------------------- cxa_guard.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+260
-182
@@ -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
|
||||
@@ -38,28 +44,31 @@
|
||||
*/
|
||||
|
||||
#include "__cxxabi_config.h"
|
||||
#include "include/atomic_support.h"
|
||||
#include <unistd.h>
|
||||
#include "include/atomic_support.h" // from libc++
|
||||
#if defined(__has_include)
|
||||
# if __has_include(<sys/syscall.h>)
|
||||
# include <sys/syscall.h>
|
||||
# endif
|
||||
# if __has_include(<sys/syscall.h>)
|
||||
# include <sys/syscall.h>
|
||||
# endif
|
||||
# if __has_include(<unistd.h>)
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <__threading_support>
|
||||
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||
#if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||
#pragma comment(lib, "pthread")
|
||||
#endif
|
||||
# if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB)
|
||||
# pragma comment(lib, "pthread")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Waddress"
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Waddress"
|
||||
#endif
|
||||
|
||||
// To make testing possible, this header is included from both cxa_guard.cpp
|
||||
@@ -74,20 +83,20 @@
|
||||
// defined when including this file. Only `src/cxa_guard.cpp` should define
|
||||
// the former.
|
||||
#ifdef BUILDING_CXA_GUARD
|
||||
# include "abort_message.h"
|
||||
# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
|
||||
# include "abort_message.h"
|
||||
# define ABORT_WITH_MESSAGE(...) ::abort_message(__VA_ARGS__)
|
||||
#elif defined(TESTING_CXA_GUARD)
|
||||
# define ABORT_WITH_MESSAGE(...) ::abort()
|
||||
# define ABORT_WITH_MESSAGE(...) ::abort()
|
||||
#else
|
||||
# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
|
||||
# error "Either BUILDING_CXA_GUARD or TESTING_CXA_GUARD must be defined"
|
||||
#endif
|
||||
|
||||
#if __has_feature(thread_sanitizer)
|
||||
extern "C" void __tsan_acquire(void*);
|
||||
extern "C" void __tsan_release(void*);
|
||||
#else
|
||||
#define __tsan_acquire(addr) ((void)0)
|
||||
#define __tsan_release(addr) ((void)0)
|
||||
# define __tsan_acquire(addr) ((void)0)
|
||||
# define __tsan_release(addr) ((void)0)
|
||||
#endif
|
||||
|
||||
namespace __cxxabiv1 {
|
||||
@@ -99,7 +108,7 @@ namespace {
|
||||
// Misc Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <class T, T(*Init)()>
|
||||
template <class T, T (*Init)()>
|
||||
struct LazyValue {
|
||||
LazyValue() : is_init(false) {}
|
||||
|
||||
@@ -110,7 +119,8 @@ struct LazyValue {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
private:
|
||||
|
||||
private:
|
||||
T value;
|
||||
bool is_init = false;
|
||||
};
|
||||
@@ -120,25 +130,19 @@ class AtomicInt {
|
||||
public:
|
||||
using MemoryOrder = std::__libcpp_atomic_order;
|
||||
|
||||
explicit AtomicInt(IntType *b) : b_(b) {}
|
||||
explicit AtomicInt(IntType* b) : b_(b) {}
|
||||
AtomicInt(AtomicInt const&) = delete;
|
||||
AtomicInt& operator=(AtomicInt const&) = delete;
|
||||
|
||||
IntType load(MemoryOrder ord) {
|
||||
return std::__libcpp_atomic_load(b_, ord);
|
||||
}
|
||||
void store(IntType val, MemoryOrder ord) {
|
||||
std::__libcpp_atomic_store(b_, val, ord);
|
||||
}
|
||||
IntType exchange(IntType new_val, MemoryOrder ord) {
|
||||
return std::__libcpp_atomic_exchange(b_, new_val, ord);
|
||||
}
|
||||
bool compare_exchange(IntType *expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
|
||||
IntType load(MemoryOrder ord) { return std::__libcpp_atomic_load(b_, ord); }
|
||||
void store(IntType val, MemoryOrder ord) { std::__libcpp_atomic_store(b_, val, ord); }
|
||||
IntType exchange(IntType new_val, MemoryOrder ord) { return std::__libcpp_atomic_exchange(b_, new_val, ord); }
|
||||
bool compare_exchange(IntType* expected, IntType desired, MemoryOrder ord_success, MemoryOrder ord_failure) {
|
||||
return std::__libcpp_atomic_compare_exchange(b_, expected, desired, ord_success, ord_failure);
|
||||
}
|
||||
|
||||
private:
|
||||
IntType *b_;
|
||||
IntType* b_;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -148,8 +152,7 @@ private:
|
||||
#if defined(__APPLE__) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||
uint32_t PlatformThreadID() {
|
||||
static_assert(sizeof(mach_port_t) == sizeof(uint32_t), "");
|
||||
return static_cast<uint32_t>(
|
||||
pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
|
||||
return static_cast<uint32_t>(pthread_mach_thread_np(std::__libcpp_thread_get_current_id()));
|
||||
}
|
||||
#elif defined(SYS_gettid) && defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
|
||||
uint32_t PlatformThreadID() {
|
||||
@@ -160,99 +163,108 @@ 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;
|
||||
/// Manages reads and writes to the guard byte.
|
||||
struct GuardByte {
|
||||
GuardByte() = delete;
|
||||
GuardByte(GuardByte const&) = delete;
|
||||
GuardByte& operator=(GuardByte 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) {}
|
||||
|
||||
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();
|
||||
/// 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_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_release.
|
||||
void release() { guard_byte.store(COMPLETE_BIT, std::_AO_Release); }
|
||||
|
||||
/// Implements __cxa_guard_abort
|
||||
void cxa_guard_abort() { derived()->abort_init_byte(); }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Global Mutex Implementation
|
||||
@@ -280,9 +292,7 @@ struct LibcppCondVar {
|
||||
LibcppCondVar(LibcppCondVar const&) = delete;
|
||||
LibcppCondVar& operator=(LibcppCondVar const&) = delete;
|
||||
|
||||
bool wait(LibcppMutex& mut) {
|
||||
return std::__libcpp_condvar_wait(&cond, &mut.mutex);
|
||||
}
|
||||
bool wait(LibcppMutex& mut) { return std::__libcpp_condvar_wait(&cond, &mut.mutex); }
|
||||
bool broadcast() { return std::__libcpp_condvar_broadcast(&cond); }
|
||||
|
||||
private:
|
||||
@@ -293,28 +303,25 @@ 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)) {
|
||||
if (*thread_id_address == current_thread_id.get())
|
||||
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
|
||||
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
|
||||
}
|
||||
|
||||
// Wait until the pending bit is not set.
|
||||
@@ -324,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");
|
||||
@@ -347,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");
|
||||
@@ -364,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;
|
||||
|
||||
@@ -375,8 +388,7 @@ private:
|
||||
LockGuard(LockGuard const&) = delete;
|
||||
LockGuard& operator=(LockGuard const&) = delete;
|
||||
|
||||
explicit LockGuard(const char* calling_func)
|
||||
: calling_func_(calling_func) {
|
||||
explicit LockGuard(const char* calling_func) : calling_func_(calling_func) {
|
||||
if (global_mutex.lock())
|
||||
ABORT_WITH_MESSAGE("%s failed to acquire mutex", calling_func_);
|
||||
}
|
||||
@@ -411,50 +423,40 @@ constexpr void (*PlatformFutexWait)(int*, int) = nullptr;
|
||||
constexpr void (*PlatformFutexWake)(int*) = nullptr;
|
||||
#endif
|
||||
|
||||
constexpr bool PlatformSupportsFutex() {
|
||||
return +PlatformFutexWait != nullptr;
|
||||
}
|
||||
constexpr bool PlatformSupportsFutex() { return +PlatformFutexWait != nullptr; }
|
||||
|
||||
/// InitByteFutex - Manages initialization using atomics and the futex syscall
|
||||
/// for waiting and waking.
|
||||
template <void (*Wait)(int*, int) = PlatformFutexWait,
|
||||
void (*Wake)(int*) = PlatformFutexWake,
|
||||
/// 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;
|
||||
struct InitByteFutex {
|
||||
|
||||
/// 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) {}
|
||||
|
||||
/// 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 (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) {
|
||||
|
||||
// Check for recursive initialization
|
||||
if (has_thread_id_support && thread_id.load(std::_AO_Relaxed) == current_thread_id.get()) {
|
||||
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
|
||||
ABORT_WITH_MESSAGE("__cxa_guard_acquire detected recursive initialization");
|
||||
}
|
||||
|
||||
if ((last_val & WAITING_BIT) == 0) {
|
||||
@@ -462,11 +464,10 @@ public:
|
||||
// (1) another thread finished the whole thing before we got here
|
||||
// (2) another thread set the waiting bit we were trying to thread
|
||||
// (3) another thread had an exception and failed to finish
|
||||
if (!init_byte.compare_exchange(&last_val, PENDING_BIT | WAITING_BIT,
|
||||
std::_AO_Acq_Rel, std::_AO_Release)) {
|
||||
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)
|
||||
@@ -480,30 +481,30 @@ 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);
|
||||
|
||||
uint8_t old = init_byte.exchange(0, std::_AO_Acq_Rel);
|
||||
uint8_t old = init_byte.exchange(UNSET, std::_AO_Acq_Rel);
|
||||
if (old & WAITING_BIT)
|
||||
wake_all();
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -513,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.
|
||||
@@ -525,6 +530,86 @@ private:
|
||||
static_assert(Wait != nullptr && Wake != nullptr, "");
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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>>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -536,31 +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
|
||||
@@ -571,22 +650,21 @@ constexpr Implementation CurrentImplementation =
|
||||
#elif defined(_LIBCXXABI_USE_FUTEX)
|
||||
Implementation::Futex;
|
||||
#else
|
||||
Implementation::GlobalLock;
|
||||
Implementation::GlobalMutex;
|
||||
#endif
|
||||
|
||||
static_assert(CurrentImplementation != Implementation::Futex
|
||||
|| PlatformSupportsFutex(), "Futex selected but not supported");
|
||||
static_assert(CurrentImplementation != Implementation::Futex || PlatformSupportsFutex(),
|
||||
"Futex selected but not supported");
|
||||
|
||||
using SelectedImplementation =
|
||||
SelectImplementation<CurrentImplementation>::type;
|
||||
using SelectedImplementation = SelectImplementation<CurrentImplementation>::type;
|
||||
|
||||
} // end namespace
|
||||
} // end namespace __cxxabiv1
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
# pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
|
||||
|
||||
Vendored
+3
-13
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_handlers.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
//
|
||||
// This file implements the functionality associated with the terminate_handler,
|
||||
// unexpected_handler, and new_handler.
|
||||
// unexpected_handler, and new_handler.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "cxa_handlers.h"
|
||||
#include "cxa_exception.h"
|
||||
#include "private_typeinfo.h"
|
||||
#include "include/atomic_support.h"
|
||||
#include "include/atomic_support.h" // from libc++
|
||||
|
||||
namespace std
|
||||
{
|
||||
@@ -92,16 +92,6 @@ terminate() noexcept
|
||||
__terminate(get_terminate());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
new_handler __cxa_new_handler = 0;
|
||||
}
|
||||
|
||||
new_handler
|
||||
set_new_handler(new_handler handler) noexcept
|
||||
{
|
||||
return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
|
||||
}
|
||||
|
||||
new_handler
|
||||
get_new_handler() noexcept
|
||||
{
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_handlers.h -----------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_exception.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+16
-4
@@ -1,4 +1,4 @@
|
||||
//===------------------------- cxa_exception.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -1004,9 +1004,14 @@ extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,
|
||||
static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
|
||||
_Unwind_Context* context)
|
||||
{
|
||||
if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK)
|
||||
return _URC_FAILURE;
|
||||
switch (__gnu_unwind_frame(unwind_exception, context)) {
|
||||
case _URC_OK:
|
||||
return _URC_CONTINUE_UNWIND;
|
||||
case _URC_END_OF_STACK:
|
||||
return _URC_END_OF_STACK;
|
||||
default:
|
||||
return _URC_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// ARM register names
|
||||
@@ -1109,7 +1114,14 @@ __gxx_personality_v0(_Unwind_State state,
|
||||
// Either we didn't do a phase 1 search (due to forced unwinding), or
|
||||
// phase 1 reported no catching-handlers.
|
||||
// Search for a (non-catching) cleanup
|
||||
scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context);
|
||||
if (is_force_unwinding)
|
||||
scan_eh_tab(
|
||||
results,
|
||||
static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND),
|
||||
native_exception, unwind_exception, context);
|
||||
else
|
||||
scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception,
|
||||
unwind_exception, context);
|
||||
if (results.reason == _URC_HANDLER_FOUND)
|
||||
{
|
||||
// Found a non-catching handler
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===----------------------- cxa_thread_atexit.cpp ------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===-------------------------- cxa_vector.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===-------------------------- cxa_virtual.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+746
-704
@@ -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) \
|
||||
@@ -57,6 +60,7 @@
|
||||
X(LocalName) \
|
||||
X(VectorType) \
|
||||
X(PixelVectorType) \
|
||||
X(BinaryFPType) \
|
||||
X(SyntheticTemplateParamName) \
|
||||
X(TypeTemplateParamDecl) \
|
||||
X(NonTypeTemplateParamDecl) \
|
||||
@@ -109,6 +113,126 @@
|
||||
|
||||
DEMANGLE_NAMESPACE_BEGIN
|
||||
|
||||
template <class T, size_t N> class PODSmallVector {
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"T is required to be a plain old data type");
|
||||
|
||||
T *First = nullptr;
|
||||
T *Last = nullptr;
|
||||
T *Cap = nullptr;
|
||||
T Inline[N] = {0};
|
||||
|
||||
bool isInline() const { return First == Inline; }
|
||||
|
||||
void clearInline() {
|
||||
First = Inline;
|
||||
Last = Inline;
|
||||
Cap = Inline + N;
|
||||
}
|
||||
|
||||
void reserve(size_t NewCap) {
|
||||
size_t S = size();
|
||||
if (isInline()) {
|
||||
auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T)));
|
||||
if (Tmp == nullptr)
|
||||
std::terminate();
|
||||
std::copy(First, Last, Tmp);
|
||||
First = Tmp;
|
||||
} else {
|
||||
First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T)));
|
||||
if (First == nullptr)
|
||||
std::terminate();
|
||||
}
|
||||
Last = First + S;
|
||||
Cap = First + NewCap;
|
||||
}
|
||||
|
||||
public:
|
||||
PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
|
||||
|
||||
PODSmallVector(const PODSmallVector &) = delete;
|
||||
PODSmallVector &operator=(const PODSmallVector &) = delete;
|
||||
|
||||
PODSmallVector(PODSmallVector &&Other) : PODSmallVector() {
|
||||
if (Other.isInline()) {
|
||||
std::copy(Other.begin(), Other.end(), First);
|
||||
Last = First + Other.size();
|
||||
Other.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
First = Other.First;
|
||||
Last = Other.Last;
|
||||
Cap = Other.Cap;
|
||||
Other.clearInline();
|
||||
}
|
||||
|
||||
PODSmallVector &operator=(PODSmallVector &&Other) {
|
||||
if (Other.isInline()) {
|
||||
if (!isInline()) {
|
||||
std::free(First);
|
||||
clearInline();
|
||||
}
|
||||
std::copy(Other.begin(), Other.end(), First);
|
||||
Last = First + Other.size();
|
||||
Other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (isInline()) {
|
||||
First = Other.First;
|
||||
Last = Other.Last;
|
||||
Cap = Other.Cap;
|
||||
Other.clearInline();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::swap(First, Other.First);
|
||||
std::swap(Last, Other.Last);
|
||||
std::swap(Cap, Other.Cap);
|
||||
Other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
void push_back(const T &Elem) {
|
||||
if (Last == Cap)
|
||||
reserve(size() * 2);
|
||||
*Last++ = Elem;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
void pop_back() {
|
||||
assert(Last != First && "Popping empty vector!");
|
||||
--Last;
|
||||
}
|
||||
|
||||
void dropBack(size_t Index) {
|
||||
assert(Index <= size() && "dropBack() can't expand!");
|
||||
Last = First + Index;
|
||||
}
|
||||
|
||||
T *begin() { return First; }
|
||||
T *end() { return Last; }
|
||||
|
||||
bool empty() const { return First == Last; }
|
||||
size_t size() const { return static_cast<size_t>(Last - First); }
|
||||
T &back() {
|
||||
assert(Last != First && "Calling back() on empty vector!");
|
||||
return *(Last - 1);
|
||||
}
|
||||
T &operator[](size_t Index) {
|
||||
assert(Index < size() && "Invalid access!");
|
||||
return *(begin() + Index);
|
||||
}
|
||||
void clear() { Last = First; }
|
||||
|
||||
~PODSmallVector() {
|
||||
if (!isInline())
|
||||
std::free(First);
|
||||
}
|
||||
};
|
||||
|
||||
// Base class of all AST nodes. The AST is built by the parser, then is
|
||||
// traversed by the printLeft/Right functions to produce a demangled string.
|
||||
class Node {
|
||||
@@ -155,50 +279,48 @@ public:
|
||||
// would construct an equivalent node.
|
||||
//template<typename Fn> void match(Fn F) const;
|
||||
|
||||
bool hasRHSComponent(OutputStream &S) const {
|
||||
bool hasRHSComponent(OutputBuffer &OB) const {
|
||||
if (RHSComponentCache != Cache::Unknown)
|
||||
return RHSComponentCache == Cache::Yes;
|
||||
return hasRHSComponentSlow(S);
|
||||
return hasRHSComponentSlow(OB);
|
||||
}
|
||||
|
||||
bool hasArray(OutputStream &S) const {
|
||||
bool hasArray(OutputBuffer &OB) const {
|
||||
if (ArrayCache != Cache::Unknown)
|
||||
return ArrayCache == Cache::Yes;
|
||||
return hasArraySlow(S);
|
||||
return hasArraySlow(OB);
|
||||
}
|
||||
|
||||
bool hasFunction(OutputStream &S) const {
|
||||
bool hasFunction(OutputBuffer &OB) const {
|
||||
if (FunctionCache != Cache::Unknown)
|
||||
return FunctionCache == Cache::Yes;
|
||||
return hasFunctionSlow(S);
|
||||
return hasFunctionSlow(OB);
|
||||
}
|
||||
|
||||
Kind getKind() const { return K; }
|
||||
|
||||
virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
|
||||
virtual bool hasArraySlow(OutputStream &) const { return false; }
|
||||
virtual bool hasFunctionSlow(OutputStream &) const { return false; }
|
||||
virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; }
|
||||
virtual bool hasArraySlow(OutputBuffer &) const { return false; }
|
||||
virtual bool hasFunctionSlow(OutputBuffer &) 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;
|
||||
}
|
||||
virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; }
|
||||
|
||||
void print(OutputStream &S) const {
|
||||
printLeft(S);
|
||||
void print(OutputBuffer &OB) const {
|
||||
printLeft(OB);
|
||||
if (RHSComponentCache != Cache::No)
|
||||
printRight(S);
|
||||
printRight(OB);
|
||||
}
|
||||
|
||||
// Print the "left" side of this Node into OutputStream.
|
||||
virtual void printLeft(OutputStream &) const = 0;
|
||||
// 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
|
||||
// that appear on the RHS of their subtype, such as arrays or functions.
|
||||
// Since most types don't have such a component, provide a default
|
||||
// implementation.
|
||||
virtual void printRight(OutputStream &) const {}
|
||||
virtual void printRight(OutputBuffer &) const {}
|
||||
|
||||
virtual StringView getBaseName() const { return StringView(); }
|
||||
|
||||
@@ -227,19 +349,19 @@ public:
|
||||
|
||||
Node *operator[](size_t Idx) const { return Elements[Idx]; }
|
||||
|
||||
void printWithComma(OutputStream &S) const {
|
||||
void printWithComma(OutputBuffer &OB) const {
|
||||
bool FirstElement = true;
|
||||
for (size_t Idx = 0; Idx != NumElements; ++Idx) {
|
||||
size_t BeforeComma = S.getCurrentPosition();
|
||||
size_t BeforeComma = OB.getCurrentPosition();
|
||||
if (!FirstElement)
|
||||
S += ", ";
|
||||
size_t AfterComma = S.getCurrentPosition();
|
||||
Elements[Idx]->print(S);
|
||||
OB += ", ";
|
||||
size_t AfterComma = OB.getCurrentPosition();
|
||||
Elements[Idx]->print(OB);
|
||||
|
||||
// Elements[Idx] is an empty parameter pack expansion, we should erase the
|
||||
// comma we just printed.
|
||||
if (AfterComma == S.getCurrentPosition()) {
|
||||
S.setCurrentPosition(BeforeComma);
|
||||
if (AfterComma == OB.getCurrentPosition()) {
|
||||
OB.setCurrentPosition(BeforeComma);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -254,9 +376,7 @@ struct NodeArrayNode : Node {
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Array); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Array.printWithComma(S);
|
||||
}
|
||||
void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); }
|
||||
};
|
||||
|
||||
class DotSuffix final : public Node {
|
||||
@@ -269,11 +389,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); }
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
Prefix->print(s);
|
||||
s += " (";
|
||||
s += Suffix;
|
||||
s += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Prefix->print(OB);
|
||||
OB += " (";
|
||||
OB += Suffix;
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,12 +408,12 @@ public:
|
||||
|
||||
template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Ty->print(S);
|
||||
S += " ";
|
||||
S += Ext;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Ty->print(OB);
|
||||
OB += " ";
|
||||
OB += Ext;
|
||||
if (TA != nullptr)
|
||||
TA->print(S);
|
||||
TA->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -319,13 +439,13 @@ protected:
|
||||
const Qualifiers Quals;
|
||||
const Node *Child;
|
||||
|
||||
void printQuals(OutputStream &S) const {
|
||||
void printQuals(OutputBuffer &OB) const {
|
||||
if (Quals & QualConst)
|
||||
S += " const";
|
||||
OB += " const";
|
||||
if (Quals & QualVolatile)
|
||||
S += " volatile";
|
||||
OB += " volatile";
|
||||
if (Quals & QualRestrict)
|
||||
S += " restrict";
|
||||
OB += " restrict";
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -336,22 +456,22 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Child, Quals); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
return Child->hasRHSComponent(S);
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
return Child->hasRHSComponent(OB);
|
||||
}
|
||||
bool hasArraySlow(OutputStream &S) const override {
|
||||
return Child->hasArray(S);
|
||||
bool hasArraySlow(OutputBuffer &OB) const override {
|
||||
return Child->hasArray(OB);
|
||||
}
|
||||
bool hasFunctionSlow(OutputStream &S) const override {
|
||||
return Child->hasFunction(S);
|
||||
bool hasFunctionSlow(OutputBuffer &OB) const override {
|
||||
return Child->hasFunction(OB);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Child->printLeft(S);
|
||||
printQuals(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Child->printLeft(OB);
|
||||
printQuals(OB);
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override { Child->printRight(S); }
|
||||
void printRight(OutputBuffer &OB) const override { Child->printRight(OB); }
|
||||
};
|
||||
|
||||
class ConversionOperatorType final : public Node {
|
||||
@@ -363,9 +483,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Ty); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "operator ";
|
||||
Ty->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "operator ";
|
||||
Ty->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -379,9 +499,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
Ty->printLeft(s);
|
||||
s += Postfix;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Ty->printLeft(OB);
|
||||
OB += Postfix;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -396,7 +516,7 @@ public:
|
||||
StringView getName() const { return Name; }
|
||||
StringView getBaseName() const override { return Name; }
|
||||
|
||||
void printLeft(OutputStream &s) const override { s += Name; }
|
||||
void printLeft(OutputBuffer &OB) const override { OB += Name; }
|
||||
};
|
||||
|
||||
class ElaboratedTypeSpefType : public Node {
|
||||
@@ -408,10 +528,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Kind, Child); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += Kind;
|
||||
S += ' ';
|
||||
Child->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Kind;
|
||||
OB += ' ';
|
||||
Child->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -426,11 +546,11 @@ struct AbiTagAttr : Node {
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Base, Tag); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Base->printLeft(S);
|
||||
S += "[abi:";
|
||||
S += Tag;
|
||||
S += "]";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Base->printLeft(OB);
|
||||
OB += "[abi:";
|
||||
OB += Tag;
|
||||
OB += "]";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -442,10 +562,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Conditions); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += " [enable_if:";
|
||||
Conditions.printWithComma(S);
|
||||
S += ']';
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += " [enable_if:";
|
||||
Conditions.printWithComma(OB);
|
||||
OB += ']';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -466,11 +586,11 @@ public:
|
||||
static_cast<const NameType *>(Ty)->getName() == "objc_object";
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Ty->print(S);
|
||||
S += "<";
|
||||
S += Protocol;
|
||||
S += ">";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Ty->print(OB);
|
||||
OB += "<";
|
||||
OB += Protocol;
|
||||
OB += ">";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -484,34 +604,34 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Pointee); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
return Pointee->hasRHSComponent(S);
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
return Pointee->hasRHSComponent(OB);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
|
||||
if (Pointee->getKind() != KObjCProtoName ||
|
||||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
|
||||
Pointee->printLeft(s);
|
||||
if (Pointee->hasArray(s))
|
||||
s += " ";
|
||||
if (Pointee->hasArray(s) || Pointee->hasFunction(s))
|
||||
s += "(";
|
||||
s += "*";
|
||||
Pointee->printLeft(OB);
|
||||
if (Pointee->hasArray(OB))
|
||||
OB += " ";
|
||||
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
|
||||
OB += "(";
|
||||
OB += "*";
|
||||
} else {
|
||||
const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
|
||||
s += "id<";
|
||||
s += objcProto->Protocol;
|
||||
s += ">";
|
||||
OB += "id<";
|
||||
OB += objcProto->Protocol;
|
||||
OB += ">";
|
||||
}
|
||||
}
|
||||
|
||||
void printRight(OutputStream &s) const override {
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
if (Pointee->getKind() != KObjCProtoName ||
|
||||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
|
||||
if (Pointee->hasArray(s) || Pointee->hasFunction(s))
|
||||
s += ")";
|
||||
Pointee->printRight(s);
|
||||
if (Pointee->hasArray(OB) || Pointee->hasFunction(OB))
|
||||
OB += ")";
|
||||
Pointee->printRight(OB);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -531,15 +651,30 @@ class ReferenceType : public Node {
|
||||
// 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 {
|
||||
//
|
||||
// A combination of a TemplateForwardReference and a back-ref Substitution
|
||||
// from an ill-formed string may have created a cycle; use cycle detection to
|
||||
// avoid looping forever.
|
||||
std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const {
|
||||
auto SoFar = std::make_pair(RK, Pointee);
|
||||
// Track the chain of nodes for the Floyd's 'tortoise and hare'
|
||||
// cycle-detection algorithm, since getSyntaxNode(S) is impure
|
||||
PODSmallVector<const Node *, 8> Prev;
|
||||
for (;;) {
|
||||
const Node *SN = SoFar.second->getSyntaxNode(S);
|
||||
const Node *SN = SoFar.second->getSyntaxNode(OB);
|
||||
if (SN->getKind() != KReferenceType)
|
||||
break;
|
||||
auto *RT = static_cast<const ReferenceType *>(SN);
|
||||
SoFar.second = RT->Pointee;
|
||||
SoFar.first = std::min(SoFar.first, RT->RK);
|
||||
|
||||
// The middle of Prev is the 'slow' pointer moving at half speed
|
||||
Prev.push_back(SoFar.second);
|
||||
if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) {
|
||||
// Cycle detected
|
||||
SoFar.second = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SoFar;
|
||||
}
|
||||
@@ -551,31 +686,35 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Pointee, RK); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
return Pointee->hasRHSComponent(S);
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
return Pointee->hasRHSComponent(OB);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
|
||||
Collapsed.second->printLeft(s);
|
||||
if (Collapsed.second->hasArray(s))
|
||||
s += " ";
|
||||
if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
|
||||
s += "(";
|
||||
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
|
||||
if (!Collapsed.second)
|
||||
return;
|
||||
Collapsed.second->printLeft(OB);
|
||||
if (Collapsed.second->hasArray(OB))
|
||||
OB += " ";
|
||||
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
|
||||
OB += "(";
|
||||
|
||||
s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
|
||||
OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
|
||||
}
|
||||
void printRight(OutputStream &s) const override {
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
|
||||
if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
|
||||
s += ")";
|
||||
Collapsed.second->printRight(s);
|
||||
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
|
||||
if (!Collapsed.second)
|
||||
return;
|
||||
if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB))
|
||||
OB += ")";
|
||||
Collapsed.second->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -590,24 +729,24 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
return MemberType->hasRHSComponent(S);
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
return MemberType->hasRHSComponent(OB);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
MemberType->printLeft(s);
|
||||
if (MemberType->hasArray(s) || MemberType->hasFunction(s))
|
||||
s += "(";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
MemberType->printLeft(OB);
|
||||
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
|
||||
OB += "(";
|
||||
else
|
||||
s += " ";
|
||||
ClassType->print(s);
|
||||
s += "::*";
|
||||
OB += " ";
|
||||
ClassType->print(OB);
|
||||
OB += "::*";
|
||||
}
|
||||
|
||||
void printRight(OutputStream &s) const override {
|
||||
if (MemberType->hasArray(s) || MemberType->hasFunction(s))
|
||||
s += ")";
|
||||
MemberType->printRight(s);
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
if (MemberType->hasArray(OB) || MemberType->hasFunction(OB))
|
||||
OB += ")";
|
||||
MemberType->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -624,19 +763,19 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Base, Dimension); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &) const override { return true; }
|
||||
bool hasArraySlow(OutputStream &) const override { return true; }
|
||||
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
|
||||
bool hasArraySlow(OutputBuffer &) const override { return true; }
|
||||
|
||||
void printLeft(OutputStream &S) const override { Base->printLeft(S); }
|
||||
void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); }
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
if (S.back() != ']')
|
||||
S += " ";
|
||||
S += "[";
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
if (OB.back() != ']')
|
||||
OB += " ";
|
||||
OB += "[";
|
||||
if (Dimension)
|
||||
Dimension->print(S);
|
||||
S += "]";
|
||||
Base->printRight(S);
|
||||
Dimension->print(OB);
|
||||
OB += "]";
|
||||
Base->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -660,8 +799,8 @@ public:
|
||||
F(Ret, Params, CVQuals, RefQual, ExceptionSpec);
|
||||
}
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &) const override { return true; }
|
||||
bool hasFunctionSlow(OutputStream &) const override { return true; }
|
||||
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
|
||||
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
|
||||
|
||||
// Handle C++'s ... quirky decl grammar by using the left & right
|
||||
// distinction. Consider:
|
||||
@@ -670,32 +809,32 @@ public:
|
||||
// that takes a char and returns an int. If we're trying to print f, start
|
||||
// by printing out the return types's left, then print our parameters, then
|
||||
// finally print right of the return type.
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Ret->printLeft(S);
|
||||
S += " ";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Ret->printLeft(OB);
|
||||
OB += " ";
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Params.printWithComma(S);
|
||||
S += ")";
|
||||
Ret->printRight(S);
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Params.printWithComma(OB);
|
||||
OB += ")";
|
||||
Ret->printRight(OB);
|
||||
|
||||
if (CVQuals & QualConst)
|
||||
S += " const";
|
||||
OB += " const";
|
||||
if (CVQuals & QualVolatile)
|
||||
S += " volatile";
|
||||
OB += " volatile";
|
||||
if (CVQuals & QualRestrict)
|
||||
S += " restrict";
|
||||
OB += " restrict";
|
||||
|
||||
if (RefQual == FrefQualLValue)
|
||||
S += " &";
|
||||
OB += " &";
|
||||
else if (RefQual == FrefQualRValue)
|
||||
S += " &&";
|
||||
OB += " &&";
|
||||
|
||||
if (ExceptionSpec != nullptr) {
|
||||
S += ' ';
|
||||
ExceptionSpec->print(S);
|
||||
OB += ' ';
|
||||
ExceptionSpec->print(OB);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -707,10 +846,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(E); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "noexcept(";
|
||||
E->print(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "noexcept(";
|
||||
E->print(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -722,10 +861,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Types); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "throw(";
|
||||
Types.printWithComma(S);
|
||||
S += ')';
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "throw(";
|
||||
Types.printWithComma(OB);
|
||||
OB += ')';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -756,41 +895,41 @@ public:
|
||||
NodeArray getParams() const { return Params; }
|
||||
const Node *getReturnType() const { return Ret; }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &) const override { return true; }
|
||||
bool hasFunctionSlow(OutputStream &) const override { return true; }
|
||||
bool hasRHSComponentSlow(OutputBuffer &) const override { return true; }
|
||||
bool hasFunctionSlow(OutputBuffer &) const override { return true; }
|
||||
|
||||
const Node *getName() const { return Name; }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (Ret) {
|
||||
Ret->printLeft(S);
|
||||
if (!Ret->hasRHSComponent(S))
|
||||
S += " ";
|
||||
Ret->printLeft(OB);
|
||||
if (!Ret->hasRHSComponent(OB))
|
||||
OB += " ";
|
||||
}
|
||||
Name->print(S);
|
||||
Name->print(OB);
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Params.printWithComma(S);
|
||||
S += ")";
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Params.printWithComma(OB);
|
||||
OB += ")";
|
||||
if (Ret)
|
||||
Ret->printRight(S);
|
||||
Ret->printRight(OB);
|
||||
|
||||
if (CVQuals & QualConst)
|
||||
S += " const";
|
||||
OB += " const";
|
||||
if (CVQuals & QualVolatile)
|
||||
S += " volatile";
|
||||
OB += " volatile";
|
||||
if (CVQuals & QualRestrict)
|
||||
S += " restrict";
|
||||
OB += " restrict";
|
||||
|
||||
if (RefQual == FrefQualLValue)
|
||||
S += " &";
|
||||
OB += " &";
|
||||
else if (RefQual == FrefQualRValue)
|
||||
S += " &&";
|
||||
OB += " &&";
|
||||
|
||||
if (Attrs != nullptr)
|
||||
Attrs->print(S);
|
||||
Attrs->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -803,9 +942,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(OpName); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "operator\"\" ";
|
||||
OpName->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "operator\"\" ";
|
||||
OpName->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -819,9 +958,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Special, Child); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += Special;
|
||||
Child->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Special;
|
||||
Child->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -836,11 +975,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "construction vtable for ";
|
||||
FirstType->print(S);
|
||||
S += "-in-";
|
||||
SecondType->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "construction vtable for ";
|
||||
FirstType->print(OB);
|
||||
OB += "-in-";
|
||||
SecondType->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -855,10 +994,10 @@ struct NestedName : Node {
|
||||
|
||||
StringView getBaseName() const override { return Name->getBaseName(); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Qual->print(S);
|
||||
S += "::";
|
||||
Name->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Qual->print(OB);
|
||||
OB += "::";
|
||||
Name->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -871,10 +1010,10 @@ struct LocalName : Node {
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Encoding, Entity); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Encoding->print(S);
|
||||
S += "::";
|
||||
Entity->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Encoding->print(OB);
|
||||
OB += "::";
|
||||
Entity->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -891,10 +1030,10 @@ public:
|
||||
|
||||
StringView getBaseName() const override { return Name->getBaseName(); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Qualifier->print(S);
|
||||
S += "::";
|
||||
Name->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Qualifier->print(OB);
|
||||
OB += "::";
|
||||
Name->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -909,12 +1048,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
BaseType->print(S);
|
||||
S += " vector[";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
BaseType->print(OB);
|
||||
OB += " vector[";
|
||||
if (Dimension)
|
||||
Dimension->print(S);
|
||||
S += "]";
|
||||
Dimension->print(OB);
|
||||
OB += "]";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -927,11 +1066,26 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Dimension); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
// FIXME: This should demangle as "vector pixel".
|
||||
S += "pixel vector[";
|
||||
Dimension->print(S);
|
||||
S += "]";
|
||||
OB += "pixel vector[";
|
||||
Dimension->print(OB);
|
||||
OB += "]";
|
||||
}
|
||||
};
|
||||
|
||||
class BinaryFPType final : public Node {
|
||||
const Node *Dimension;
|
||||
|
||||
public:
|
||||
BinaryFPType(const Node *Dimension_)
|
||||
: Node(KBinaryFPType), Dimension(Dimension_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Dimension); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "_Float";
|
||||
Dimension->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -953,20 +1107,20 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Kind, Index); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
switch (Kind) {
|
||||
case TemplateParamKind::Type:
|
||||
S += "$T";
|
||||
OB += "$T";
|
||||
break;
|
||||
case TemplateParamKind::NonType:
|
||||
S += "$N";
|
||||
OB += "$N";
|
||||
break;
|
||||
case TemplateParamKind::Template:
|
||||
S += "$TT";
|
||||
OB += "$TT";
|
||||
break;
|
||||
}
|
||||
if (Index > 0)
|
||||
S << Index - 1;
|
||||
OB << Index - 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -980,13 +1134,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Name); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "typename ";
|
||||
}
|
||||
void printLeft(OutputBuffer &OB) const override { OB += "typename "; }
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
Name->print(S);
|
||||
}
|
||||
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
|
||||
};
|
||||
|
||||
/// A non-type template parameter declaration, 'int N'.
|
||||
@@ -1000,15 +1150,15 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Name, Type); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Type->printLeft(S);
|
||||
if (!Type->hasRHSComponent(S))
|
||||
S += " ";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Type->printLeft(OB);
|
||||
if (!Type->hasRHSComponent(OB))
|
||||
OB += " ";
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
Name->print(S);
|
||||
Type->printRight(S);
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
Name->print(OB);
|
||||
Type->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1025,15 +1175,13 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Name, Params); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "template<";
|
||||
Params.printWithComma(S);
|
||||
S += "> typename ";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "template<";
|
||||
Params.printWithComma(OB);
|
||||
OB += "> typename ";
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
Name->print(S);
|
||||
}
|
||||
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
|
||||
};
|
||||
|
||||
/// A template parameter pack declaration, 'typename ...T'.
|
||||
@@ -1046,14 +1194,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Param); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Param->printLeft(S);
|
||||
S += "...";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Param->printLeft(OB);
|
||||
OB += "...";
|
||||
}
|
||||
|
||||
void printRight(OutputStream &S) const override {
|
||||
Param->printRight(S);
|
||||
}
|
||||
void printRight(OutputBuffer &OB) const override { Param->printRight(OB); }
|
||||
};
|
||||
|
||||
/// An unexpanded parameter pack (either in the expression or type context). If
|
||||
@@ -1067,11 +1213,12 @@ public:
|
||||
class ParameterPack final : public Node {
|
||||
NodeArray Data;
|
||||
|
||||
// Setup OutputStream for a pack expansion unless we're already expanding one.
|
||||
void initializePackExpansion(OutputStream &S) const {
|
||||
if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
|
||||
S.CurrentPackMax = static_cast<unsigned>(Data.size());
|
||||
S.CurrentPackIndex = 0;
|
||||
// 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());
|
||||
OB.CurrentPackIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1094,38 +1241,38 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Data); }
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB);
|
||||
}
|
||||
bool hasArraySlow(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasArray(S);
|
||||
bool hasArraySlow(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasArray(OB);
|
||||
}
|
||||
bool hasFunctionSlow(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasFunction(S);
|
||||
bool hasFunctionSlow(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
return Idx < Data.size() && Data[Idx]->hasFunction(OB);
|
||||
}
|
||||
const Node *getSyntaxNode(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
|
||||
const Node *getSyntaxNode(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this;
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
if (Idx < Data.size())
|
||||
Data[Idx]->printLeft(S);
|
||||
Data[Idx]->printLeft(OB);
|
||||
}
|
||||
void printRight(OutputStream &S) const override {
|
||||
initializePackExpansion(S);
|
||||
size_t Idx = S.CurrentPackIndex;
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
initializePackExpansion(OB);
|
||||
size_t Idx = OB.CurrentPackIndex;
|
||||
if (Idx < Data.size())
|
||||
Data[Idx]->printRight(S);
|
||||
Data[Idx]->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1144,8 +1291,8 @@ public:
|
||||
|
||||
NodeArray getElements() const { return Elements; }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Elements.printWithComma(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Elements.printWithComma(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1162,35 +1309,35 @@ public:
|
||||
|
||||
const Node *getChild() const { return Child; }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
constexpr unsigned Max = std::numeric_limits<unsigned>::max();
|
||||
SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);
|
||||
SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);
|
||||
size_t StreamPos = S.getCurrentPosition();
|
||||
SwapAndRestore<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
|
||||
SwapAndRestore<unsigned> SavePackMax(OB.CurrentPackMax, Max);
|
||||
size_t StreamPos = OB.getCurrentPosition();
|
||||
|
||||
// Print the first element in the pack. If Child contains a ParameterPack,
|
||||
// it will set up S.CurrentPackMax and print the first element.
|
||||
Child->print(S);
|
||||
Child->print(OB);
|
||||
|
||||
// No ParameterPack was found in Child. This can occur if we've found a pack
|
||||
// expansion on a <function-param>.
|
||||
if (S.CurrentPackMax == Max) {
|
||||
S += "...";
|
||||
if (OB.CurrentPackMax == Max) {
|
||||
OB += "...";
|
||||
return;
|
||||
}
|
||||
|
||||
// We found a ParameterPack, but it has no elements. Erase whatever we may
|
||||
// of printed.
|
||||
if (S.CurrentPackMax == 0) {
|
||||
S.setCurrentPosition(StreamPos);
|
||||
if (OB.CurrentPackMax == 0) {
|
||||
OB.setCurrentPosition(StreamPos);
|
||||
return;
|
||||
}
|
||||
|
||||
// Else, iterate through the rest of the elements in the pack.
|
||||
for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
|
||||
S += ", ";
|
||||
S.CurrentPackIndex = I;
|
||||
Child->print(S);
|
||||
for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) {
|
||||
OB += ", ";
|
||||
OB.CurrentPackIndex = I;
|
||||
Child->print(OB);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1205,12 +1352,12 @@ public:
|
||||
|
||||
NodeArray getParams() { return Params; }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "<";
|
||||
Params.printWithComma(S);
|
||||
if (S.back() == '>')
|
||||
S += " ";
|
||||
S += ">";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "<";
|
||||
Params.printWithComma(OB);
|
||||
if (OB.back() == '>')
|
||||
OB += " ";
|
||||
OB += ">";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1252,42 +1399,42 @@ struct ForwardTemplateReference : Node {
|
||||
// special handling.
|
||||
template<typename Fn> void match(Fn F) const = delete;
|
||||
|
||||
bool hasRHSComponentSlow(OutputStream &S) const override {
|
||||
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return false;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
return Ref->hasRHSComponent(S);
|
||||
return Ref->hasRHSComponent(OB);
|
||||
}
|
||||
bool hasArraySlow(OutputStream &S) const override {
|
||||
bool hasArraySlow(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return false;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
return Ref->hasArray(S);
|
||||
return Ref->hasArray(OB);
|
||||
}
|
||||
bool hasFunctionSlow(OutputStream &S) const override {
|
||||
bool hasFunctionSlow(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return false;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
return Ref->hasFunction(S);
|
||||
return Ref->hasFunction(OB);
|
||||
}
|
||||
const Node *getSyntaxNode(OutputStream &S) const override {
|
||||
const Node *getSyntaxNode(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return this;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
return Ref->getSyntaxNode(S);
|
||||
return Ref->getSyntaxNode(OB);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
Ref->printLeft(S);
|
||||
Ref->printLeft(OB);
|
||||
}
|
||||
void printRight(OutputStream &S) const override {
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
if (Printing)
|
||||
return;
|
||||
SwapAndRestore<bool> SavePrinting(Printing, true);
|
||||
Ref->printRight(S);
|
||||
Ref->printRight(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1303,9 +1450,9 @@ struct NameWithTemplateArgs : Node {
|
||||
|
||||
StringView getBaseName() const override { return Name->getBaseName(); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Name->print(S);
|
||||
TemplateArgs->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Name->print(OB);
|
||||
TemplateArgs->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1320,9 +1467,9 @@ public:
|
||||
|
||||
StringView getBaseName() const override { return Child->getBaseName(); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "::";
|
||||
Child->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "::";
|
||||
Child->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1335,9 +1482,9 @@ struct StdQualifiedName : Node {
|
||||
|
||||
StringView getBaseName() const override { return Child->getBaseName(); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "std::";
|
||||
Child->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "std::";
|
||||
Child->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1377,26 +1524,26 @@ public:
|
||||
DEMANGLE_UNREACHABLE;
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
switch (SSK) {
|
||||
case SpecialSubKind::allocator:
|
||||
S += "std::allocator";
|
||||
OB += "std::allocator";
|
||||
break;
|
||||
case SpecialSubKind::basic_string:
|
||||
S += "std::basic_string";
|
||||
OB += "std::basic_string";
|
||||
break;
|
||||
case SpecialSubKind::string:
|
||||
S += "std::basic_string<char, std::char_traits<char>, "
|
||||
"std::allocator<char> >";
|
||||
OB += "std::basic_string<char, std::char_traits<char>, "
|
||||
"std::allocator<char> >";
|
||||
break;
|
||||
case SpecialSubKind::istream:
|
||||
S += "std::basic_istream<char, std::char_traits<char> >";
|
||||
OB += "std::basic_istream<char, std::char_traits<char> >";
|
||||
break;
|
||||
case SpecialSubKind::ostream:
|
||||
S += "std::basic_ostream<char, std::char_traits<char> >";
|
||||
OB += "std::basic_ostream<char, std::char_traits<char> >";
|
||||
break;
|
||||
case SpecialSubKind::iostream:
|
||||
S += "std::basic_iostream<char, std::char_traits<char> >";
|
||||
OB += "std::basic_iostream<char, std::char_traits<char> >";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1429,25 +1576,25 @@ public:
|
||||
DEMANGLE_UNREACHABLE;
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
switch (SSK) {
|
||||
case SpecialSubKind::allocator:
|
||||
S += "std::allocator";
|
||||
OB += "std::allocator";
|
||||
break;
|
||||
case SpecialSubKind::basic_string:
|
||||
S += "std::basic_string";
|
||||
OB += "std::basic_string";
|
||||
break;
|
||||
case SpecialSubKind::string:
|
||||
S += "std::string";
|
||||
OB += "std::string";
|
||||
break;
|
||||
case SpecialSubKind::istream:
|
||||
S += "std::istream";
|
||||
OB += "std::istream";
|
||||
break;
|
||||
case SpecialSubKind::ostream:
|
||||
S += "std::ostream";
|
||||
OB += "std::ostream";
|
||||
break;
|
||||
case SpecialSubKind::iostream:
|
||||
S += "std::iostream";
|
||||
OB += "std::iostream";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1465,10 +1612,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (IsDtor)
|
||||
S += "~";
|
||||
S += Basename->getBaseName();
|
||||
OB += "~";
|
||||
OB += Basename->getBaseName();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1480,9 +1627,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Base); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "~";
|
||||
Base->printLeft(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "~";
|
||||
Base->printLeft(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1494,10 +1641,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Count); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "'unnamed";
|
||||
S += Count;
|
||||
S += "\'";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "'unnamed";
|
||||
OB += Count;
|
||||
OB += "\'";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1516,22 +1663,22 @@ public:
|
||||
F(TemplateParams, Params, Count);
|
||||
}
|
||||
|
||||
void printDeclarator(OutputStream &S) const {
|
||||
void printDeclarator(OutputBuffer &OB) const {
|
||||
if (!TemplateParams.empty()) {
|
||||
S += "<";
|
||||
TemplateParams.printWithComma(S);
|
||||
S += ">";
|
||||
OB += "<";
|
||||
TemplateParams.printWithComma(OB);
|
||||
OB += ">";
|
||||
}
|
||||
S += "(";
|
||||
Params.printWithComma(S);
|
||||
S += ")";
|
||||
OB += "(";
|
||||
Params.printWithComma(OB);
|
||||
OB += ")";
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "\'lambda";
|
||||
S += Count;
|
||||
S += "\'";
|
||||
printDeclarator(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "\'lambda";
|
||||
OB += Count;
|
||||
OB += "\'";
|
||||
printDeclarator(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1543,10 +1690,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Bindings); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += '[';
|
||||
Bindings.printWithComma(S);
|
||||
S += ']';
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += '[';
|
||||
Bindings.printWithComma(OB);
|
||||
OB += ']';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1564,22 +1711,22 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
// might be a template argument expression, then we need to disambiguate
|
||||
// with parens.
|
||||
if (InfixOperator == ">")
|
||||
S += "(";
|
||||
OB += "(";
|
||||
|
||||
S += "(";
|
||||
LHS->print(S);
|
||||
S += ") ";
|
||||
S += InfixOperator;
|
||||
S += " (";
|
||||
RHS->print(S);
|
||||
S += ")";
|
||||
OB += "(";
|
||||
LHS->print(OB);
|
||||
OB += ") ";
|
||||
OB += InfixOperator;
|
||||
OB += " (";
|
||||
RHS->print(OB);
|
||||
OB += ")";
|
||||
|
||||
if (InfixOperator == ">")
|
||||
S += ")";
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1593,12 +1740,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Op1, Op2); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Op1->print(S);
|
||||
S += ")[";
|
||||
Op2->print(S);
|
||||
S += "]";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Op1->print(OB);
|
||||
OB += ")[";
|
||||
Op2->print(OB);
|
||||
OB += "]";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1612,11 +1759,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Child, Operator); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Child->print(S);
|
||||
S += ")";
|
||||
S += Operator;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Child->print(OB);
|
||||
OB += ")";
|
||||
OB += Operator;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1631,14 +1778,14 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Cond->print(S);
|
||||
S += ") ? (";
|
||||
Then->print(S);
|
||||
S += ") : (";
|
||||
Else->print(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Cond->print(OB);
|
||||
OB += ") ? (";
|
||||
Then->print(OB);
|
||||
OB += ") : (";
|
||||
Else->print(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1653,10 +1800,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
LHS->print(S);
|
||||
S += Kind;
|
||||
RHS->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
LHS->print(OB);
|
||||
OB += Kind;
|
||||
RHS->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1677,20 +1824,20 @@ public:
|
||||
F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
SubExpr->print(S);
|
||||
S += ".<";
|
||||
Type->print(S);
|
||||
S += " at offset ";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
SubExpr->print(OB);
|
||||
OB += ".<";
|
||||
Type->print(OB);
|
||||
OB += " at offset ";
|
||||
if (Offset.empty()) {
|
||||
S += "0";
|
||||
OB += "0";
|
||||
} else if (Offset[0] == 'n') {
|
||||
S += "-";
|
||||
S += Offset.dropFront();
|
||||
OB += "-";
|
||||
OB += Offset.dropFront();
|
||||
} else {
|
||||
S += Offset;
|
||||
OB += Offset;
|
||||
}
|
||||
S += ">";
|
||||
OB += ">";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1706,10 +1853,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += Prefix;
|
||||
Infix->print(S);
|
||||
S += Postfix;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Prefix;
|
||||
Infix->print(OB);
|
||||
OB += Postfix;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1725,13 +1872,13 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(CastKind, To, From); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += CastKind;
|
||||
S += "<";
|
||||
To->printLeft(S);
|
||||
S += ">(";
|
||||
From->printLeft(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += CastKind;
|
||||
OB += "<";
|
||||
To->printLeft(OB);
|
||||
OB += ">(";
|
||||
From->printLeft(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1744,11 +1891,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Pack); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "sizeof...(";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "sizeof...(";
|
||||
ParameterPackExpansion PPE(Pack);
|
||||
PPE.printLeft(S);
|
||||
S += ")";
|
||||
PPE.printLeft(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1762,11 +1909,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Callee, Args); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
Callee->print(S);
|
||||
S += "(";
|
||||
Args.printWithComma(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Callee->print(OB);
|
||||
OB += "(";
|
||||
Args.printWithComma(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1787,25 +1934,24 @@ public:
|
||||
F(ExprList, Type, InitList, IsGlobal, IsArray);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (IsGlobal)
|
||||
S += "::operator ";
|
||||
S += "new";
|
||||
OB += "::operator ";
|
||||
OB += "new";
|
||||
if (IsArray)
|
||||
S += "[]";
|
||||
S += ' ';
|
||||
OB += "[]";
|
||||
OB += ' ';
|
||||
if (!ExprList.empty()) {
|
||||
S += "(";
|
||||
ExprList.printWithComma(S);
|
||||
S += ")";
|
||||
OB += "(";
|
||||
ExprList.printWithComma(OB);
|
||||
OB += ")";
|
||||
}
|
||||
Type->print(S);
|
||||
Type->print(OB);
|
||||
if (!InitList.empty()) {
|
||||
S += "(";
|
||||
InitList.printWithComma(S);
|
||||
S += ")";
|
||||
OB += "(";
|
||||
InitList.printWithComma(OB);
|
||||
OB += ")";
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1820,13 +1966,13 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (IsGlobal)
|
||||
S += "::";
|
||||
S += "delete";
|
||||
OB += "::";
|
||||
OB += "delete";
|
||||
if (IsArray)
|
||||
S += "[] ";
|
||||
Op->print(S);
|
||||
OB += "[] ";
|
||||
Op->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1840,11 +1986,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Prefix, Child); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += Prefix;
|
||||
S += "(";
|
||||
Child->print(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Prefix;
|
||||
OB += "(";
|
||||
Child->print(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1856,9 +2002,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Number); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "fp";
|
||||
S += Number;
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "fp";
|
||||
OB += Number;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1872,12 +2018,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Type, Expressions); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Type->print(S);
|
||||
S += ")(";
|
||||
Expressions.printWithComma(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Type->print(OB);
|
||||
OB += ")(";
|
||||
Expressions.printWithComma(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1894,12 +2040,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Type, SubExpr, Offset); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "(";
|
||||
Type->print(S);
|
||||
S += ")(";
|
||||
SubExpr->print(S);
|
||||
S += ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "(";
|
||||
Type->print(OB);
|
||||
OB += ")(";
|
||||
SubExpr->print(OB);
|
||||
OB += ")";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1912,12 +2058,12 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Ty, Inits); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (Ty)
|
||||
Ty->print(S);
|
||||
S += '{';
|
||||
Inits.printWithComma(S);
|
||||
S += '}';
|
||||
Ty->print(OB);
|
||||
OB += '{';
|
||||
Inits.printWithComma(OB);
|
||||
OB += '}';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1931,18 +2077,18 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (IsArray) {
|
||||
S += '[';
|
||||
Elem->print(S);
|
||||
S += ']';
|
||||
OB += '[';
|
||||
Elem->print(OB);
|
||||
OB += ']';
|
||||
} else {
|
||||
S += '.';
|
||||
Elem->print(S);
|
||||
OB += '.';
|
||||
Elem->print(OB);
|
||||
}
|
||||
if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
|
||||
S += " = ";
|
||||
Init->print(S);
|
||||
OB += " = ";
|
||||
Init->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1956,15 +2102,15 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(First, Last, Init); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += '[';
|
||||
First->print(S);
|
||||
S += " ... ";
|
||||
Last->print(S);
|
||||
S += ']';
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += '[';
|
||||
First->print(OB);
|
||||
OB += " ... ";
|
||||
Last->print(OB);
|
||||
OB += ']';
|
||||
if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
|
||||
S += " = ";
|
||||
Init->print(S);
|
||||
OB += " = ";
|
||||
Init->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1983,43 +2129,43 @@ public:
|
||||
F(IsLeftFold, OperatorName, Pack, Init);
|
||||
}
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
auto PrintPack = [&] {
|
||||
S += '(';
|
||||
ParameterPackExpansion(Pack).print(S);
|
||||
S += ')';
|
||||
OB += '(';
|
||||
ParameterPackExpansion(Pack).print(OB);
|
||||
OB += ')';
|
||||
};
|
||||
|
||||
S += '(';
|
||||
OB += '(';
|
||||
|
||||
if (IsLeftFold) {
|
||||
// init op ... op pack
|
||||
if (Init != nullptr) {
|
||||
Init->print(S);
|
||||
S += ' ';
|
||||
S += OperatorName;
|
||||
S += ' ';
|
||||
Init->print(OB);
|
||||
OB += ' ';
|
||||
OB += OperatorName;
|
||||
OB += ' ';
|
||||
}
|
||||
// ... op pack
|
||||
S += "... ";
|
||||
S += OperatorName;
|
||||
S += ' ';
|
||||
OB += "... ";
|
||||
OB += OperatorName;
|
||||
OB += ' ';
|
||||
PrintPack();
|
||||
} else { // !IsLeftFold
|
||||
// pack op ...
|
||||
PrintPack();
|
||||
S += ' ';
|
||||
S += OperatorName;
|
||||
S += " ...";
|
||||
OB += ' ';
|
||||
OB += OperatorName;
|
||||
OB += " ...";
|
||||
// pack op ... op init
|
||||
if (Init != nullptr) {
|
||||
S += ' ';
|
||||
S += OperatorName;
|
||||
S += ' ';
|
||||
Init->print(S);
|
||||
OB += ' ';
|
||||
OB += OperatorName;
|
||||
OB += ' ';
|
||||
Init->print(OB);
|
||||
}
|
||||
}
|
||||
S += ')';
|
||||
OB += ')';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2031,9 +2177,9 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Op); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "throw ";
|
||||
Op->print(S);
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "throw ";
|
||||
Op->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2045,8 +2191,8 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Value); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += Value ? StringView("true") : StringView("false");
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Value ? StringView("true") : StringView("false");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2058,10 +2204,10 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Type); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "\"<";
|
||||
Type->print(S);
|
||||
S += ">\"";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "\"<";
|
||||
Type->print(OB);
|
||||
OB += ">\"";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2073,11 +2219,11 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Type); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S += "[]";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "[]";
|
||||
if (Type->getKind() == KClosureTypeName)
|
||||
static_cast<const ClosureTypeName *>(Type)->printDeclarator(S);
|
||||
S += "{...}";
|
||||
static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB);
|
||||
OB += "{...}";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2092,15 +2238,15 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
S << "(";
|
||||
Ty->print(S);
|
||||
S << ")";
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB << "(";
|
||||
Ty->print(OB);
|
||||
OB << ")";
|
||||
|
||||
if (Integer[0] == 'n')
|
||||
S << "-" << Integer.dropFront(1);
|
||||
OB << "-" << Integer.dropFront(1);
|
||||
else
|
||||
S << Integer;
|
||||
OB << Integer;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2114,21 +2260,21 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Type, Value); }
|
||||
|
||||
void printLeft(OutputStream &S) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
if (Type.size() > 3) {
|
||||
S += "(";
|
||||
S += Type;
|
||||
S += ")";
|
||||
OB += "(";
|
||||
OB += Type;
|
||||
OB += ")";
|
||||
}
|
||||
|
||||
if (Value[0] == 'n') {
|
||||
S += "-";
|
||||
S += Value.dropFront(1);
|
||||
OB += "-";
|
||||
OB += Value.dropFront(1);
|
||||
} else
|
||||
S += Value;
|
||||
OB += Value;
|
||||
|
||||
if (Type.size() <= 3)
|
||||
S += Type;
|
||||
OB += Type;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2158,7 +2304,7 @@ public:
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Contents); }
|
||||
|
||||
void printLeft(OutputStream &s) const override {
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
const char *first = Contents.begin();
|
||||
const char *last = Contents.end() + 1;
|
||||
|
||||
@@ -2184,7 +2330,7 @@ public:
|
||||
#endif
|
||||
char num[FloatData<Float>::max_demangled_size] = {0};
|
||||
int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);
|
||||
s += StringView(num, num + n);
|
||||
OB += StringView(num, num + n);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2217,125 +2363,6 @@ FOR_EACH_NODE_KIND(SPECIALIZATION)
|
||||
|
||||
#undef FOR_EACH_NODE_KIND
|
||||
|
||||
template <class T, size_t N>
|
||||
class PODSmallVector {
|
||||
static_assert(std::is_pod<T>::value,
|
||||
"T is required to be a plain old data type");
|
||||
|
||||
T* First = nullptr;
|
||||
T* Last = nullptr;
|
||||
T* Cap = nullptr;
|
||||
T Inline[N] = {0};
|
||||
|
||||
bool isInline() const { return First == Inline; }
|
||||
|
||||
void clearInline() {
|
||||
First = Inline;
|
||||
Last = Inline;
|
||||
Cap = Inline + N;
|
||||
}
|
||||
|
||||
void reserve(size_t NewCap) {
|
||||
size_t S = size();
|
||||
if (isInline()) {
|
||||
auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
|
||||
if (Tmp == nullptr)
|
||||
std::terminate();
|
||||
std::copy(First, Last, Tmp);
|
||||
First = Tmp;
|
||||
} else {
|
||||
First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
|
||||
if (First == nullptr)
|
||||
std::terminate();
|
||||
}
|
||||
Last = First + S;
|
||||
Cap = First + NewCap;
|
||||
}
|
||||
|
||||
public:
|
||||
PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
|
||||
|
||||
PODSmallVector(const PODSmallVector&) = delete;
|
||||
PODSmallVector& operator=(const PODSmallVector&) = delete;
|
||||
|
||||
PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
|
||||
if (Other.isInline()) {
|
||||
std::copy(Other.begin(), Other.end(), First);
|
||||
Last = First + Other.size();
|
||||
Other.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
First = Other.First;
|
||||
Last = Other.Last;
|
||||
Cap = Other.Cap;
|
||||
Other.clearInline();
|
||||
}
|
||||
|
||||
PODSmallVector& operator=(PODSmallVector&& Other) {
|
||||
if (Other.isInline()) {
|
||||
if (!isInline()) {
|
||||
std::free(First);
|
||||
clearInline();
|
||||
}
|
||||
std::copy(Other.begin(), Other.end(), First);
|
||||
Last = First + Other.size();
|
||||
Other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (isInline()) {
|
||||
First = Other.First;
|
||||
Last = Other.Last;
|
||||
Cap = Other.Cap;
|
||||
Other.clearInline();
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::swap(First, Other.First);
|
||||
std::swap(Last, Other.Last);
|
||||
std::swap(Cap, Other.Cap);
|
||||
Other.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void push_back(const T& Elem) {
|
||||
if (Last == Cap)
|
||||
reserve(size() * 2);
|
||||
*Last++ = Elem;
|
||||
}
|
||||
|
||||
void pop_back() {
|
||||
assert(Last != First && "Popping empty vector!");
|
||||
--Last;
|
||||
}
|
||||
|
||||
void dropBack(size_t Index) {
|
||||
assert(Index <= size() && "dropBack() can't expand!");
|
||||
Last = First + Index;
|
||||
}
|
||||
|
||||
T* begin() { return First; }
|
||||
T* end() { return Last; }
|
||||
|
||||
bool empty() const { return First == Last; }
|
||||
size_t size() const { return static_cast<size_t>(Last - First); }
|
||||
T& back() {
|
||||
assert(Last != First && "Calling back() on empty vector!");
|
||||
return *(Last - 1);
|
||||
}
|
||||
T& operator[](size_t Index) {
|
||||
assert(Index < size() && "Invalid access!");
|
||||
return *(begin() + Index);
|
||||
}
|
||||
void clear() { Last = First; }
|
||||
|
||||
~PODSmallVector() {
|
||||
if (!isInline())
|
||||
std::free(First);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
const char *First;
|
||||
const char *Last;
|
||||
@@ -2450,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];
|
||||
@@ -2568,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 *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);
|
||||
}
|
||||
if (Result == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (look() == 'I') {
|
||||
// ::= <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>(S, 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;
|
||||
}
|
||||
|
||||
Node *N = getDerived().parseUnscopedName(State);
|
||||
if (N == nullptr)
|
||||
return nullptr;
|
||||
// ::= <unscoped-template-name> <template-args>
|
||||
if (look() == 'I') {
|
||||
Subs.push_back(N);
|
||||
Node *TA = getDerived().parseTemplateArgs(State != nullptr);
|
||||
if (TA == nullptr)
|
||||
return nullptr;
|
||||
if (State) State->EndsWithTemplateArgs = true;
|
||||
return make<NameWithTemplateArgs>(N, TA);
|
||||
}
|
||||
// ::= <unscoped-name>
|
||||
return N;
|
||||
return Result;
|
||||
}
|
||||
|
||||
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
|
||||
@@ -2640,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]
|
||||
@@ -3884,6 +3919,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
|
||||
case 'h':
|
||||
First += 2;
|
||||
return make<NameType>("half");
|
||||
// ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits)
|
||||
case 'F': {
|
||||
First += 2;
|
||||
Node *DimensionNumber = make<NameType>(parseNumber());
|
||||
if (!DimensionNumber)
|
||||
return nullptr;
|
||||
if (!consumeIf('_'))
|
||||
return nullptr;
|
||||
return make<BinaryFPType>(DimensionNumber);
|
||||
}
|
||||
// ::= Di # char32_t
|
||||
case 'i':
|
||||
First += 2;
|
||||
@@ -4031,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:
|
||||
@@ -4050,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;
|
||||
}
|
||||
@@ -5404,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);
|
||||
break;
|
||||
case 's':
|
||||
++First;
|
||||
SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
|
||||
break;
|
||||
case 'i':
|
||||
++First;
|
||||
SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
|
||||
break;
|
||||
case 'o':
|
||||
++First;
|
||||
SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
|
||||
Kind = SpecialSubKind::basic_string;
|
||||
break;
|
||||
case 'd':
|
||||
++First;
|
||||
SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
|
||||
Kind = SpecialSubKind::iostream;
|
||||
break;
|
||||
case 'i':
|
||||
Kind = SpecialSubKind::istream;
|
||||
break;
|
||||
case 'o':
|
||||
Kind = SpecialSubKind::ostream;
|
||||
break;
|
||||
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.
|
||||
|
||||
+10
-7
@@ -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
|
||||
|
||||
Vendored
+45
-20
@@ -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,17 +17,18 @@
|
||||
#define DEMANGLE_UTILITY_H
|
||||
|
||||
#include "StringView.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <exception>
|
||||
#include <limits>
|
||||
|
||||
DEMANGLE_NAMESPACE_BEGIN
|
||||
|
||||
// Stream that AST nodes write their string representation into after the AST
|
||||
// has been parsed.
|
||||
class OutputStream {
|
||||
class OutputBuffer {
|
||||
char *Buffer = nullptr;
|
||||
size_t CurrentPosition = 0;
|
||||
size_t BufferCapacity = 0;
|
||||
@@ -48,8 +52,8 @@ class OutputStream {
|
||||
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,13 +63,13 @@ class OutputStream {
|
||||
// Add negative sign...
|
||||
if (isNeg)
|
||||
*--TempPtr = '-';
|
||||
this->operator<<(StringView(TempPtr, std::end(Temp)));
|
||||
this->operator<<(StringView(TempPtr, Temp.data() + Temp.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
OutputStream(char *StartBuf, size_t Size)
|
||||
OutputBuffer(char *StartBuf, size_t Size)
|
||||
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
|
||||
OutputStream() = default;
|
||||
OutputBuffer() = default;
|
||||
void reset(char *Buffer_, size_t BufferCapacity_) {
|
||||
CurrentPosition = 0;
|
||||
Buffer = Buffer_;
|
||||
@@ -77,7 +81,7 @@ public:
|
||||
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
|
||||
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
|
||||
|
||||
OutputStream &operator+=(StringView R) {
|
||||
OutputBuffer &operator+=(StringView R) {
|
||||
size_t Size = R.size();
|
||||
if (Size == 0)
|
||||
return *this;
|
||||
@@ -87,17 +91,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator+=(char C) {
|
||||
OutputBuffer &operator+=(char C) {
|
||||
grow(1);
|
||||
Buffer[CurrentPosition++] = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(StringView R) { return (*this += R); }
|
||||
OutputBuffer &operator<<(StringView R) { return (*this += R); }
|
||||
|
||||
OutputStream &operator<<(char C) { return (*this += C); }
|
||||
OutputBuffer prepend(StringView R) {
|
||||
size_t Size = R.size();
|
||||
|
||||
OutputStream &operator<<(long long N) {
|
||||
grow(Size);
|
||||
std::memmove(Buffer + Size, Buffer, CurrentPosition);
|
||||
std::memcpy(Buffer, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(char C) { return (*this += C); }
|
||||
|
||||
OutputBuffer &operator<<(long long N) {
|
||||
if (N < 0)
|
||||
writeUnsigned(static_cast<unsigned long long>(-N), true);
|
||||
else
|
||||
@@ -105,27 +120,37 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned long long N) {
|
||||
OutputBuffer &operator<<(unsigned long long N) {
|
||||
writeUnsigned(N, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(long N) {
|
||||
OutputBuffer &operator<<(long N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned long N) {
|
||||
OutputBuffer &operator<<(unsigned long N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(int N) {
|
||||
OutputBuffer &operator<<(int N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned int N) {
|
||||
OutputBuffer &operator<<(unsigned int N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
void insert(size_t Pos, const char *S, size_t N) {
|
||||
assert(Pos <= CurrentPosition);
|
||||
if (N == 0)
|
||||
return;
|
||||
grow(N);
|
||||
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
|
||||
std::memcpy(Buffer + Pos, S, N);
|
||||
CurrentPosition += N;
|
||||
}
|
||||
|
||||
size_t getCurrentPosition() const { return CurrentPosition; }
|
||||
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||
|
||||
@@ -171,7 +196,7 @@ public:
|
||||
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
|
||||
};
|
||||
|
||||
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
|
||||
inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
|
||||
size_t InitSize) {
|
||||
size_t BufferSize;
|
||||
if (Buf == nullptr) {
|
||||
@@ -182,7 +207,7 @@ inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
|
||||
} else
|
||||
BufferSize = *N;
|
||||
|
||||
S.reset(Buf, BufferSize);
|
||||
OB.reset(Buf, BufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------ fallback_malloc.cpp -------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------- fallback_malloc.h --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
//===----------------------------------------------------------------------===////
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===////
|
||||
|
||||
// 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 = _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
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===----------------------- private_typeinfo.cpp -------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===------------------------ private_typeinfo.h --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===---------------------------- exception.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===--------------------- stdlib_new_delete.cpp --------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
+2
-4
@@ -1,4 +1,4 @@
|
||||
//===------------------------ stdexcept.cpp -------------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -12,9 +12,7 @@
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
// This includes an implementation file from libc++.
|
||||
#include "../../libcxx/src/include/refstring.h"
|
||||
#include "include/refstring.h" // from libc++
|
||||
|
||||
static_assert(sizeof(std::__libcpp_refstring) == sizeof(const char *), "");
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//===----------------------------- typeinfo.cpp ---------------------------===//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
Reference in New Issue
Block a user