aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordtorilov <dtorilov@yandex-team.com>2024-03-27 22:11:00 +0300
committerdtorilov <dtorilov@yandex-team.com>2024-03-27 22:22:53 +0300
commit1541ebf4e489185a3ec0d47a2ea8e474522af784 (patch)
treeede807c00af640aa49309701d98b496a4d46859c
parent0a9f70229b9ddccbd4a09d389642ddafcbe8fd57 (diff)
downloadydb-1541ebf4e489185a3ec0d47a2ea8e474522af784.tar.gz
Update libcxxabi to 16.0.6
0a9e5a8cb8cd8cd03641221da29e1186a61cf984
-rw-r--r--contrib/libs/cxxsupp/libcxxabi-parts/ya.make4
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/include/__cxxabi_config.h8
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/include/cxxabi.h6
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_default_handlers.cpp115
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_demangle.cpp49
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.cpp31
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.h12
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h8
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/cxa_personality.cpp25
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h2307
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumNodes.def95
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h137
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/src/fallback_malloc.cpp75
-rw-r--r--contrib/libs/cxxsupp/libcxxabi/ya.make4
-rw-r--r--util/system/type_name_ut.cpp12
-rw-r--r--util/system/ut/ya.make7
16 files changed, 1427 insertions, 1468 deletions
diff --git a/contrib/libs/cxxsupp/libcxxabi-parts/ya.make b/contrib/libs/cxxsupp/libcxxabi-parts/ya.make
index f0928bbce5..ffcb60dd9b 100644
--- a/contrib/libs/cxxsupp/libcxxabi-parts/ya.make
+++ b/contrib/libs/cxxsupp/libcxxabi-parts/ya.make
@@ -8,9 +8,9 @@ LICENSE(
LLVM-exception
)
-VERSION(14.0.6)
+VERSION(16.0.6)
-ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/archive/llvmorg-14.0.6.tar.gz)
+ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/archive/llvmorg-16.0.6.tar.gz)
ADDINCL(
contrib/libs/cxxsupp/libcxxabi/include
diff --git a/contrib/libs/cxxsupp/libcxxabi/include/__cxxabi_config.h b/contrib/libs/cxxsupp/libcxxabi/include/__cxxabi_config.h
index 7bc39ada8d..c97dd656e1 100644
--- a/contrib/libs/cxxsupp/libcxxabi/include/__cxxabi_config.h
+++ b/contrib/libs/cxxsupp/libcxxabi/include/__cxxabi_config.h
@@ -10,7 +10,7 @@
#define ____CXXABI_CONFIG_H
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
- !defined(__ARM_DWARF_EH__)
+ !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
#define _LIBCXXABI_ARM_EHABI
#endif
@@ -97,4 +97,10 @@
# define _LIBCXXABI_NO_EXCEPTIONS
#endif
+#if defined(_WIN32)
+#define _LIBCXXABI_DTOR_FUNC __thiscall
+#else
+#define _LIBCXXABI_DTOR_FUNC
+#endif
+
#endif // ____CXXABI_CONFIG_H
diff --git a/contrib/libs/cxxsupp/libcxxabi/include/cxxabi.h b/contrib/libs/cxxsupp/libcxxabi/include/cxxabi.h
index 106c4508c4..d05c523cab 100644
--- a/contrib/libs/cxxsupp/libcxxabi/include/cxxabi.h
+++ b/contrib/libs/cxxsupp/libcxxabi/include/cxxabi.h
@@ -19,7 +19,7 @@
#include <__cxxabi_config.h>
-#define _LIBCPPABI_VERSION 1002
+#define _LIBCPPABI_VERSION 15000
#define _LIBCXXABI_NORETURN __attribute__((noreturn))
#define _LIBCXXABI_ALWAYS_COLD __attribute__((cold))
@@ -55,11 +55,11 @@ __cxa_free_exception(void *thrown_exception) _NOEXCEPT;
#ifdef __USING_WASM_EXCEPTIONS__
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
- void *(*dest)(void *));
+ void *(_LIBCXXABI_DTOR_FUNC *dest)(void *));
#else
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
- void (*dest)(void *));
+ void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
#endif
// 2.5.3 Exception Handlers
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_default_handlers.cpp b/contrib/libs/cxxsupp/libcxxabi/src/cxa_default_handlers.cpp
index e0ccbe1195..7bcfca069f 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_default_handlers.cpp
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_default_handlers.cpp
@@ -10,6 +10,7 @@
//===----------------------------------------------------------------------===//
#include <exception>
+#include <memory>
#include <stdlib.h>
#include "abort_message.h"
#include "cxxabi.h"
@@ -20,67 +21,69 @@
#if !defined(LIBCXXABI_SILENT_TERMINATE)
-_LIBCPP_SAFE_STATIC
-static const char* cause = "uncaught";
+static constinit const char* cause = "uncaught";
+
+#ifndef _LIBCXXABI_NO_EXCEPTIONS
+// Demangle the given string, or return the string as-is in case of an error.
+static std::unique_ptr<char const, void (*)(char const*)> demangle(char const* str)
+{
+#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
+ if (const char* result = __cxxabiv1::__cxa_demangle(str, nullptr, nullptr, nullptr))
+ return {result, [](char const* p) { std::free(const_cast<char*>(p)); }};
+#endif
+ return {str, [](char const*) { /* nothing to free */ }};
+}
__attribute__((noreturn))
static void demangling_terminate_handler()
{
-#ifndef _LIBCXXABI_NO_EXCEPTIONS
- // If there might be an uncaught exception
using namespace __cxxabiv1;
__cxa_eh_globals* globals = __cxa_get_globals_fast();
- if (globals)
+
+ // If there is no uncaught exception, just note that we're terminating
+ if (!globals)
+ abort_message("terminating");
+
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ if (!exception_header)
+ abort_message("terminating");
+
+ _Unwind_Exception* unwind_exception =
+ reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
+
+ // If we're terminating due to a foreign exception
+ if (!__isOurExceptionClass(unwind_exception))
+ abort_message("terminating due to %s foreign exception", cause);
+
+ void* thrown_object =
+ __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
+ ((__cxa_dependent_exception*)exception_header)->primaryException :
+ exception_header + 1;
+ const __shim_type_info* thrown_type =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ auto name = demangle(thrown_type->name());
+ // If the uncaught exception can be caught with std::exception&
+ const __shim_type_info* catch_type =
+ static_cast<const __shim_type_info*>(&typeid(std::exception));
+ if (catch_type->can_catch(thrown_type, thrown_object))
{
- __cxa_exception* exception_header = globals->caughtExceptions;
- // If there is an uncaught exception
- if (exception_header)
- {
- _Unwind_Exception* unwind_exception =
- reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
- if (__isOurExceptionClass(unwind_exception))
- {
- void* thrown_object =
- __getExceptionClass(unwind_exception) == kOurDependentExceptionClass ?
- ((__cxa_dependent_exception*)exception_header)->primaryException :
- exception_header + 1;
- const __shim_type_info* thrown_type =
- static_cast<const __shim_type_info*>(exception_header->exceptionType);
-#if !defined(LIBCXXABI_NON_DEMANGLING_TERMINATE)
- // Try to get demangled name of thrown_type
- int status;
- char buf[1024];
- size_t len = sizeof(buf);
- const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
- if (status != 0)
- name = thrown_type->name();
-#else
- const char* name = thrown_type->name();
-#endif
- // If the uncaught exception can be caught with std::exception&
- const __shim_type_info* catch_type =
- static_cast<const __shim_type_info*>(&typeid(std::exception));
- if (catch_type->can_catch(thrown_type, thrown_object))
- {
- // Include the what() message from the exception
- const std::exception* e = static_cast<const std::exception*>(thrown_object);
- abort_message("terminating with %s exception of type %s: %s",
- cause, name, e->what());
- }
- else
- // Else just note that we're terminating with an exception
- abort_message("terminating with %s exception of type %s",
- cause, name);
- }
- else
- // Else we're terminating with a foreign exception
- abort_message("terminating with %s foreign exception", cause);
- }
+ // Include the what() message from the exception
+ const std::exception* e = static_cast<const std::exception*>(thrown_object);
+ abort_message("terminating due to %s exception of type %s: %s", cause, name.get(), e->what());
}
-#endif
- // Else just note that we're terminating
+ else
+ {
+ // Else just note that we're terminating due to an exception
+ abort_message("terminating due to %s exception of type %s", cause, name.get());
+ }
+}
+#else // !_LIBCXXABI_NO_EXCEPTIONS
+__attribute__((noreturn))
+static void demangling_terminate_handler()
+{
abort_message("terminating");
}
+#endif // !_LIBCXXABI_NO_EXCEPTIONS
__attribute__((noreturn))
static void demangling_unexpected_handler()
@@ -91,22 +94,22 @@ static void demangling_unexpected_handler()
static constexpr std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static constexpr std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
-#else
+#else // !LIBCXXABI_SILENT_TERMINATE
static constexpr std::terminate_handler default_terminate_handler = ::abort;
static constexpr std::terminate_handler default_unexpected_handler = std::terminate;
-#endif
+#endif // !LIBCXXABI_SILENT_TERMINATE
//
// Global variables that hold the pointers to the current handler
//
_LIBCXXABI_DATA_VIS
-_LIBCPP_SAFE_STATIC std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
+constinit std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
_LIBCXXABI_DATA_VIS
-_LIBCPP_SAFE_STATIC std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
+constinit std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
_LIBCXXABI_DATA_VIS
-_LIBCPP_SAFE_STATIC std::new_handler __cxa_new_handler = 0;
+constinit std::new_handler __cxa_new_handler = nullptr;
namespace std
{
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_demangle.cpp b/contrib/libs/cxxsupp/libcxxabi/src/cxa_demangle.cpp
index bee4cfd5a1..7baac68007 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_demangle.cpp
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_demangle.cpp
@@ -173,6 +173,50 @@ struct DumpVisitor {
return printStr("TemplateParamKind::Template");
}
}
+ void print(Node::Prec P) {
+ switch (P) {
+ case Node::Prec::Primary:
+ return printStr("Node::Prec::Primary");
+ case Node::Prec::Postfix:
+ return printStr("Node::Prec::Postfix");
+ case Node::Prec::Unary:
+ return printStr("Node::Prec::Unary");
+ case Node::Prec::Cast:
+ return printStr("Node::Prec::Cast");
+ case Node::Prec::PtrMem:
+ return printStr("Node::Prec::PtrMem");
+ case Node::Prec::Multiplicative:
+ return printStr("Node::Prec::Multiplicative");
+ case Node::Prec::Additive:
+ return printStr("Node::Prec::Additive");
+ case Node::Prec::Shift:
+ return printStr("Node::Prec::Shift");
+ case Node::Prec::Spaceship:
+ return printStr("Node::Prec::Spaceship");
+ case Node::Prec::Relational:
+ return printStr("Node::Prec::Relational");
+ case Node::Prec::Equality:
+ return printStr("Node::Prec::Equality");
+ case Node::Prec::And:
+ return printStr("Node::Prec::And");
+ case Node::Prec::Xor:
+ return printStr("Node::Prec::Xor");
+ case Node::Prec::Ior:
+ return printStr("Node::Prec::Ior");
+ case Node::Prec::AndIf:
+ return printStr("Node::Prec::AndIf");
+ case Node::Prec::OrIf:
+ return printStr("Node::Prec::OrIf");
+ case Node::Prec::Conditional:
+ return printStr("Node::Prec::Conditional");
+ case Node::Prec::Assign:
+ return printStr("Node::Prec::Assign");
+ case Node::Prec::Comma:
+ return printStr("Node::Prec::Comma");
+ case Node::Prec::Default:
+ return printStr("Node::Prec::Default");
+ }
+ }
void newLine() {
printStr("\n");
@@ -342,15 +386,12 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
- OutputBuffer O;
-
Node *AST = Parser.parse();
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
- else if (!initializeOutputBuffer(Buf, N, O, 1024))
- InternalStatus = demangle_memory_alloc_failure;
else {
+ OutputBuffer O(Buf, N);
assert(Parser.ForwardTemplateRefs.empty());
AST->print(O);
O += '\0';
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.cpp b/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.cpp
index 82123825af..6c6732b9cf 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.cpp
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.cpp
@@ -275,7 +275,7 @@ void
// In wasm, destructors return their argument
__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *))
#else
-__cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
+__cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *))
#endif
{
__cxa_eh_globals *globals = __cxa_get_globals();
@@ -390,10 +390,11 @@ 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 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.
+first argument to _Unwind_Resume(). The function also saves/restores r4 to
+keep the stack aligned and to provide a temp register. _Unwind_Resume never
+returns and we need to keep the original lr so just branch to it. When
+targeting bare metal, the function also clobbers ip/r12 to hold the address of
+_Unwind_Resume, which may be too far away for an ordinary branch.
*/
__attribute__((used)) static _Unwind_Exception *
__cxa_end_cleanup_impl()
@@ -430,15 +431,19 @@ asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n"
#if defined(__ARM_FEATURE_BTI_DEFAULT)
" bti\n"
#endif
- " push {r1, r2, r3, lr}\n"
+ " push {r1, r2, r3, r4}\n"
+ " mov r4, lr\n"
" bl __cxa_end_cleanup_impl\n"
- " pop {r1, r2, r3, r4}\n"
" mov lr, r4\n"
#if defined(LIBCXXABI_BAREMETAL)
" ldr r4, =_Unwind_Resume\n"
- " bx r4\n"
+ " mov ip, r4\n"
+#endif
+ " pop {r1, r2, r3, r4}\n"
+#if defined(LIBCXXABI_BAREMETAL)
+ " bx ip\n"
#else
- " b _Unwind_Resume\n"
+ " b _Unwind_Resume\n"
#endif
" .popsection");
#endif // defined(_LIBCXXABI_ARM_EHABI)
@@ -493,6 +498,14 @@ __cxa_begin_catch(void* unwind_arg) _NOEXCEPT
(
static_cast<_Unwind_Exception*>(unwind_exception)
);
+
+#if defined(__MVS__)
+ // Remove the exception object from the linked list of exceptions that the z/OS unwinder
+ // maintains before adding it to the libc++abi list of caught exceptions.
+ // The libc++abi will manage the lifetime of the exception from this point forward.
+ _UnwindZOS_PopException();
+#endif
+
if (native_exception)
{
// Increment the handler count, removing the flag about being rethrown
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.h b/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.h
index 4d1770c314..dd20ba1e88 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_exception.h
@@ -53,7 +53,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// in the beginning of the struct, rather than before unwindHeader.
void *reserve;
- // This is a new field to support C++ 0x exception_ptr.
+ // This is a new field to support C++11 exception_ptr.
// For binary compatibility it is at the start of this
// struct which is prepended to the object thrown in
// __cxa_allocate_exception.
@@ -64,9 +64,9 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
std::type_info *exceptionType;
#ifdef __USING_WASM_EXCEPTIONS__
// In wasm, destructors return their argument
- void *(*exceptionDestructor)(void *);
+ void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#else
- void (*exceptionDestructor)(void *);
+ void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#endif
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
@@ -87,9 +87,9 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
#endif
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
- // This is a new field to support C++ 0x exception_ptr.
+ // This is a new field to support C++11 exception_ptr.
// For binary compatibility it is placed where the compiler
- // previously adding padded to 64-bit align unwindHeader.
+ // previously added padding to 64-bit align unwindHeader.
size_t referenceCount;
#endif
_Unwind_Exception unwindHeader;
@@ -105,7 +105,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#endif
std::type_info *exceptionType;
- void (*exceptionDestructor)(void *);
+ void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h b/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
index 5a7cbfd5cd..47fe2b20bd 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_guard_impl.h
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+
#ifndef LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
#define LIBCXXABI_SRC_INCLUDE_CXA_GUARD_IMPL_H
@@ -54,9 +55,12 @@
# endif
#endif
+#include <__threading_support>
+#include <cstdint>
+#include <cstring>
#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")
@@ -619,7 +623,7 @@ struct GlobalStatic {
static T instance;
};
template <class T>
-_LIBCPP_SAFE_STATIC T GlobalStatic<T>::instance = {};
+_LIBCPP_CONSTINIT T GlobalStatic<T>::instance = {};
enum class Implementation { NoThreads, GlobalMutex, Futex };
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/cxa_personality.cpp b/contrib/libs/cxxsupp/libcxxabi/src/cxa_personality.cpp
index 12387bd7ad..1a969265f0 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/cxa_personality.cpp
+++ b/contrib/libs/cxxsupp/libcxxabi/src/cxa_personality.cpp
@@ -22,6 +22,15 @@
#include "private_typeinfo.h"
#include "unwind.h"
+// TODO: This is a temporary workaround for libc++abi to recognize that it's being
+// built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
+// in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove
+// this workaround, it won't be possible to build libc++abi against libunwind headers
+// from LLVM 14 and before anymore.
+#if defined(____LIBUNWIND_CONFIG_H__) && !defined(_LIBUNWIND_VERSION)
+# define _LIBUNWIND_VERSION
+#endif
+
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
#include <windows.h>
#include <winnt.h>
@@ -615,7 +624,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
results.reason = _URC_FATAL_PHASE1_ERROR;
return;
}
- // Start scan by getting exception table address
+ // Start scan by getting exception table address.
const uint8_t *lsda = (const uint8_t *)_Unwind_GetLanguageSpecificData(context);
if (lsda == 0)
{
@@ -907,6 +916,8 @@ static _Unwind_Reason_Code __gxx_personality_imp
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
#ifdef __USING_SJLJ_EXCEPTIONS__
__gxx_personality_sj0
+#elif defined(__MVS__)
+__zos_cxx_personality_v2
#else
__gxx_personality_v0
#endif
@@ -1024,7 +1035,7 @@ static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception,
}
// ARM register names
-#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
+#if !defined(_LIBUNWIND_VERSION)
static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block
#endif
static const uint32_t REG_SP = 13;
@@ -1059,7 +1070,7 @@ __gxx_personality_v0(_Unwind_State state,
bool native_exception = __isOurExceptionClass(unwind_exception);
-#if !defined(LIBCXXABI_USE_LLVM_UNWINDER)
+#if !defined(_LIBUNWIND_VERSION)
// Copy the address of _Unwind_Control_Block to r12 so that
// _Unwind_GetLanguageSpecificData() and _Unwind_GetRegionStart() can
// return correct address.
@@ -1121,7 +1132,7 @@ __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.
+ // phase 1 reported no catching-handlers.
// Search for a (non-catching) cleanup
if (is_force_unwinding)
scan_eh_tab(
@@ -1305,3 +1316,9 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
} // extern "C"
} // __cxxabiv1
+
+#if defined(_AIX)
+// Include implementation of the personality and helper functions for the
+// state table based EH used by IBM legacy compilers xlC and xlclang++ on AIX.
+# error #include "aix_state_tab_eh.inc"
+#endif
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
index 9b909cd0a8..2f62aa65de 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -16,10 +16,6 @@
#ifndef DEMANGLE_ITANIUMDEMANGLE_H
#define DEMANGLE_ITANIUMDEMANGLE_H
-// FIXME: (possibly) incomplete list of features that clang mangles that this
-// file does not yet support:
-// - C++ modules TS
-
#include "DemangleConfig.h"
#include "StringView.h"
#include "Utility.h"
@@ -30,88 +26,10 @@
#include <cstdlib>
#include <cstring>
#include <limits>
+#include <new>
#include <type_traits>
#include <utility>
-#define FOR_EACH_NODE_KIND(X) \
- X(NodeArrayNode) \
- X(DotSuffix) \
- X(VendorExtQualType) \
- X(QualType) \
- X(ConversionOperatorType) \
- X(PostfixQualifiedType) \
- X(ElaboratedTypeSpefType) \
- X(NameType) \
- X(AbiTagAttr) \
- X(EnableIfAttr) \
- X(ObjCProtoName) \
- X(PointerType) \
- X(ReferenceType) \
- X(PointerToMemberType) \
- X(ArrayType) \
- X(FunctionType) \
- X(NoexceptSpec) \
- X(DynamicExceptionSpec) \
- X(FunctionEncoding) \
- X(LiteralOperator) \
- X(SpecialName) \
- X(CtorVtableSpecialName) \
- X(QualifiedName) \
- X(NestedName) \
- X(LocalName) \
- X(VectorType) \
- X(PixelVectorType) \
- X(BinaryFPType) \
- X(SyntheticTemplateParamName) \
- X(TypeTemplateParamDecl) \
- X(NonTypeTemplateParamDecl) \
- X(TemplateTemplateParamDecl) \
- X(TemplateParamPackDecl) \
- X(ParameterPack) \
- X(TemplateArgumentPack) \
- X(ParameterPackExpansion) \
- X(TemplateArgs) \
- X(ForwardTemplateReference) \
- X(NameWithTemplateArgs) \
- X(GlobalQualifiedName) \
- X(StdQualifiedName) \
- X(ExpandedSpecialSubstitution) \
- X(SpecialSubstitution) \
- X(CtorDtorName) \
- X(DtorName) \
- X(UnnamedTypeName) \
- X(ClosureTypeName) \
- X(StructuredBindingName) \
- X(BinaryExpr) \
- X(ArraySubscriptExpr) \
- X(PostfixExpr) \
- X(ConditionalExpr) \
- X(MemberExpr) \
- X(SubobjectExpr) \
- X(EnclosingExpr) \
- X(CastExpr) \
- X(SizeofParamPackExpr) \
- X(CallExpr) \
- X(NewExpr) \
- X(DeleteExpr) \
- X(PrefixExpr) \
- X(FunctionParam) \
- X(ConversionExpr) \
- X(PointerToMemberConversionExpr) \
- X(InitListExpr) \
- X(FoldExpr) \
- X(ThrowExpr) \
- X(BoolExpr) \
- X(StringLiteral) \
- X(LambdaExpr) \
- X(EnumLiteral) \
- X(IntegerLiteral) \
- X(FloatLiteral) \
- X(DoubleLiteral) \
- X(LongDoubleLiteral) \
- X(BracedExpr) \
- X(BracedRangeExpr)
-
DEMANGLE_NAMESPACE_BEGIN
template <class T, size_t N> class PODSmallVector {
@@ -239,37 +157,68 @@ public:
class Node {
public:
enum Kind : unsigned char {
-#define ENUMERATOR(NodeKind) K ## NodeKind,
- FOR_EACH_NODE_KIND(ENUMERATOR)
-#undef ENUMERATOR
+#define NODE(NodeKind) K##NodeKind,
+#include "ItaniumNodes.def"
};
/// Three-way bool to track a cached value. Unknown is possible if this node
/// has an unexpanded parameter pack below it that may affect this cache.
enum class Cache : unsigned char { Yes, No, Unknown, };
+ /// Operator precedence for expression nodes. Used to determine required
+ /// parens in expression emission.
+ enum class Prec {
+ Primary,
+ Postfix,
+ Unary,
+ Cast,
+ PtrMem,
+ Multiplicative,
+ Additive,
+ Shift,
+ Spaceship,
+ Relational,
+ Equality,
+ And,
+ Xor,
+ Ior,
+ AndIf,
+ OrIf,
+ Conditional,
+ Assign,
+ Comma,
+ Default,
+ };
+
private:
Kind K;
+ Prec Precedence : 6;
+
// FIXME: Make these protected.
public:
/// Tracks if this node has a component on its right side, in which case we
/// need to call printRight.
- Cache RHSComponentCache;
+ Cache RHSComponentCache : 2;
/// Track if this node is a (possibly qualified) array type. This can affect
/// how we format the output string.
- Cache ArrayCache;
+ Cache ArrayCache : 2;
/// Track if this node is a (possibly qualified) function type. This can
/// affect how we format the output string.
- Cache FunctionCache;
+ Cache FunctionCache : 2;
public:
- Node(Kind K_, Cache RHSComponentCache_ = Cache::No,
- Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)
- : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
- FunctionCache(FunctionCache_) {}
+ Node(Kind K_, Prec Precedence_ = Prec::Primary,
+ Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No,
+ Cache FunctionCache_ = Cache::No)
+ : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_),
+ ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {}
+ Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No,
+ Cache FunctionCache_ = Cache::No)
+ : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_,
+ FunctionCache_) {}
/// Visit the most-derived object corresponding to this object.
template<typename Fn> void visit(Fn F) const;
@@ -300,6 +249,8 @@ public:
Kind getKind() const { return K; }
+ Prec getPrecedence() const { return Precedence; }
+
virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; }
virtual bool hasArraySlow(OutputBuffer &) const { return false; }
virtual bool hasFunctionSlow(OutputBuffer &) const { return false; }
@@ -308,6 +259,19 @@ public:
// get at a node that actually represents some concrete syntax.
virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; }
+ // Print this node as an expression operand, surrounding it in parentheses if
+ // its precedence is [Strictly] weaker than P.
+ void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default,
+ bool StrictlyWorse = false) const {
+ bool Paren =
+ unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse);
+ if (Paren)
+ OB.printOpen();
+ print(OB);
+ if (Paren)
+ OB.printClose();
+ }
+
void print(OutputBuffer &OB) const {
printLeft(OB);
if (RHSComponentCache != Cache::No)
@@ -357,7 +321,7 @@ public:
if (!FirstElement)
OB += ", ";
size_t AfterComma = OB.getCurrentPosition();
- Elements[Idx]->print(OB);
+ Elements[Idx]->printAsOperand(OB, Node::Prec::Comma);
// Elements[Idx] is an empty parameter pack expansion, we should erase the
// comma we just printed.
@@ -407,6 +371,10 @@ public:
VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_)
: Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {}
+ const Node *getTy() const { return Ty; }
+ StringView getExt() const { return Ext; }
+ const Node *getTA() const { return TA; }
+
template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); }
void printLeft(OutputBuffer &OB) const override {
@@ -455,6 +423,9 @@ public:
Child_->ArrayCache, Child_->FunctionCache),
Quals(Quals_), Child(Child_) {}
+ Qualifiers getQuals() const { return Quals; }
+ const Node *getChild() const { return Child; }
+
template<typename Fn> void match(Fn F) const { F(Child, Quals); }
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
@@ -495,7 +466,7 @@ class PostfixQualifiedType final : public Node {
const StringView Postfix;
public:
- PostfixQualifiedType(Node *Ty_, StringView Postfix_)
+ PostfixQualifiedType(const Node *Ty_, StringView Postfix_)
: Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {}
template<typename Fn> void match(Fn F) const { F(Ty, Postfix); }
@@ -520,6 +491,26 @@ public:
void printLeft(OutputBuffer &OB) const override { OB += Name; }
};
+class BitIntType final : public Node {
+ const Node *Size;
+ bool Signed;
+
+public:
+ BitIntType(const Node *Size_, bool Signed_)
+ : Node(KBitIntType), Size(Size_), Signed(Signed_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Size, Signed); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (!Signed)
+ OB += "unsigned ";
+ OB += "_BitInt";
+ OB.printOpen();
+ Size->printAsOperand(OB);
+ OB.printClose();
+ }
+};
+
class ElaboratedTypeSpefType : public Node {
StringView Kind;
Node *Child;
@@ -603,6 +594,8 @@ public:
: Node(KPointerType, Pointee_->RHSComponentCache),
Pointee(Pointee_) {}
+ const Node *getPointee() const { return Pointee; }
+
template<typename Fn> void match(Fn F) const { F(Pointee); }
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
@@ -694,7 +687,7 @@ public:
void printLeft(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
if (!Collapsed.second)
return;
@@ -709,7 +702,7 @@ public:
void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB);
if (!Collapsed.second)
return;
@@ -816,9 +809,9 @@ public:
}
void printRight(OutputBuffer &OB) const override {
- OB += "(";
+ OB.printOpen();
Params.printWithComma(OB);
- OB += ")";
+ OB.printClose();
Ret->printRight(OB);
if (CVQuals & QualConst)
@@ -848,9 +841,10 @@ public:
template<typename Fn> void match(Fn F) const { F(E); }
void printLeft(OutputBuffer &OB) const override {
- OB += "noexcept(";
- E->print(OB);
- OB += ")";
+ OB += "noexcept";
+ OB.printOpen();
+ E->printAsOperand(OB);
+ OB.printClose();
}
};
@@ -863,9 +857,10 @@ public:
template<typename Fn> void match(Fn F) const { F(Types); }
void printLeft(OutputBuffer &OB) const override {
- OB += "throw(";
+ OB += "throw";
+ OB.printOpen();
Types.printWithComma(OB);
- OB += ')';
+ OB.printClose();
}
};
@@ -911,9 +906,9 @@ public:
}
void printRight(OutputBuffer &OB) const override {
- OB += "(";
+ OB.printOpen();
Params.printWithComma(OB);
- OB += ")";
+ OB.printClose();
if (Ret)
Ret->printRight(OB);
@@ -1002,6 +997,46 @@ struct NestedName : Node {
}
};
+struct ModuleName : Node {
+ ModuleName *Parent;
+ Node *Name;
+ bool IsPartition;
+
+ ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false)
+ : Node(KModuleName), Parent(Parent_), Name(Name_),
+ IsPartition(IsPartition_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Parent, Name, IsPartition);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ if (Parent)
+ Parent->print(OB);
+ if (Parent || IsPartition)
+ OB += IsPartition ? ':' : '.';
+ Name->print(OB);
+ }
+};
+
+struct ModuleEntity : Node {
+ ModuleName *Module;
+ Node *Name;
+
+ ModuleEntity(ModuleName *Module_, Node *Name_)
+ : Node(KModuleEntity), Module(Module_), Name(Name_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Module, Name); }
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Name->print(OB);
+ OB += '@';
+ Module->print(OB);
+ }
+};
+
struct LocalName : Node {
Node *Encoding;
Node *Entity;
@@ -1043,9 +1078,11 @@ class VectorType final : public Node {
const Node *Dimension;
public:
- VectorType(const Node *BaseType_, Node *Dimension_)
- : Node(KVectorType), BaseType(BaseType_),
- Dimension(Dimension_) {}
+ VectorType(const Node *BaseType_, const Node *Dimension_)
+ : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {}
+
+ const Node *getBaseType() const { return BaseType; }
+ const Node *getDimension() const { return Dimension; }
template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); }
@@ -1177,6 +1214,7 @@ public:
template<typename Fn> void match(Fn F) const { F(Name, Params); }
void printLeft(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "template<";
Params.printWithComma(OB);
OB += "> typename ";
@@ -1312,8 +1350,8 @@ public:
void printLeft(OutputBuffer &OB) const override {
constexpr unsigned Max = std::numeric_limits<unsigned>::max();
- SwapAndRestore<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
- SwapAndRestore<unsigned> SavePackMax(OB.CurrentPackMax, Max);
+ ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max);
+ ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max);
size_t StreamPos = OB.getCurrentPosition();
// Print the first element in the pack. If Child contains a ParameterPack,
@@ -1354,10 +1392,9 @@ public:
NodeArray getParams() { return Params; }
void printLeft(OutputBuffer &OB) const override {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "<";
Params.printWithComma(OB);
- if (OB.back() == '>')
- OB += " ";
OB += ">";
}
};
@@ -1403,38 +1440,38 @@ struct ForwardTemplateReference : Node {
bool hasRHSComponentSlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
return Ref->hasRHSComponent(OB);
}
bool hasArraySlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
return Ref->hasArray(OB);
}
bool hasFunctionSlow(OutputBuffer &OB) const override {
if (Printing)
return false;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
return Ref->hasFunction(OB);
}
const Node *getSyntaxNode(OutputBuffer &OB) const override {
if (Printing)
return this;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
return Ref->getSyntaxNode(OB);
}
void printLeft(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
Ref->printLeft(OB);
}
void printRight(OutputBuffer &OB) const override {
if (Printing)
return;
- SwapAndRestore<bool> SavePrinting(Printing, true);
+ ScopedOverride<bool> SavePrinting(Printing, true);
Ref->printRight(OB);
}
};
@@ -1474,21 +1511,6 @@ public:
}
};
-struct StdQualifiedName : Node {
- Node *Child;
-
- StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
-
- template<typename Fn> void match(Fn F) const { F(Child); }
-
- StringView getBaseName() const override { return Child->getBaseName(); }
-
- void printLeft(OutputBuffer &OB) const override {
- OB += "std::";
- Child->print(OB);
- }
-};
-
enum class SpecialSubKind {
allocator,
basic_string,
@@ -1498,15 +1520,25 @@ enum class SpecialSubKind {
iostream,
};
-class ExpandedSpecialSubstitution final : public Node {
+class SpecialSubstitution;
+class ExpandedSpecialSubstitution : public Node {
+protected:
SpecialSubKind SSK;
+ ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_)
+ : Node(K_), SSK(SSK_) {}
public:
ExpandedSpecialSubstitution(SpecialSubKind SSK_)
- : Node(KExpandedSpecialSubstitution), SSK(SSK_) {}
+ : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {}
+ inline ExpandedSpecialSubstitution(SpecialSubstitution const *);
template<typename Fn> void match(Fn F) const { F(SSK); }
+protected:
+ bool isInstantiation() const {
+ return unsigned(SSK) >= unsigned(SpecialSubKind::string);
+ }
+
StringView getBaseName() const override {
switch (SSK) {
case SpecialSubKind::allocator:
@@ -1525,82 +1557,44 @@ public:
DEMANGLE_UNREACHABLE;
}
+private:
void printLeft(OutputBuffer &OB) const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- OB += "std::allocator";
- break;
- case SpecialSubKind::basic_string:
- OB += "std::basic_string";
- break;
- case SpecialSubKind::string:
- OB += "std::basic_string<char, std::char_traits<char>, "
- "std::allocator<char> >";
- break;
- case SpecialSubKind::istream:
- OB += "std::basic_istream<char, std::char_traits<char> >";
- break;
- case SpecialSubKind::ostream:
- OB += "std::basic_ostream<char, std::char_traits<char> >";
- break;
- case SpecialSubKind::iostream:
- OB += "std::basic_iostream<char, std::char_traits<char> >";
- break;
+ OB << "std::" << getBaseName();
+ if (isInstantiation()) {
+ OB << "<char, std::char_traits<char>";
+ if (SSK == SpecialSubKind::string)
+ OB << ", std::allocator<char>";
+ OB << ">";
}
}
};
-class SpecialSubstitution final : public Node {
+class SpecialSubstitution final : public ExpandedSpecialSubstitution {
public:
- SpecialSubKind SSK;
-
SpecialSubstitution(SpecialSubKind SSK_)
- : Node(KSpecialSubstitution), SSK(SSK_) {}
+ : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {}
template<typename Fn> void match(Fn F) const { F(SSK); }
StringView getBaseName() const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- return StringView("allocator");
- case SpecialSubKind::basic_string:
- return StringView("basic_string");
- case SpecialSubKind::string:
- return StringView("string");
- case SpecialSubKind::istream:
- return StringView("istream");
- case SpecialSubKind::ostream:
- return StringView("ostream");
- case SpecialSubKind::iostream:
- return StringView("iostream");
+ auto SV = ExpandedSpecialSubstitution::getBaseName ();
+ if (isInstantiation()) {
+ // The instantiations are typedefs that drop the "basic_" prefix.
+ assert(SV.startsWith("basic_"));
+ SV = SV.dropFront(sizeof("basic_") - 1);
}
- DEMANGLE_UNREACHABLE;
+ return SV;
}
void printLeft(OutputBuffer &OB) const override {
- switch (SSK) {
- case SpecialSubKind::allocator:
- OB += "std::allocator";
- break;
- case SpecialSubKind::basic_string:
- OB += "std::basic_string";
- break;
- case SpecialSubKind::string:
- OB += "std::string";
- break;
- case SpecialSubKind::istream:
- OB += "std::istream";
- break;
- case SpecialSubKind::ostream:
- OB += "std::ostream";
- break;
- case SpecialSubKind::iostream:
- OB += "std::iostream";
- break;
- }
+ OB << "std::" << getBaseName();
}
};
+inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution(
+ SpecialSubstitution const *SS)
+ : ExpandedSpecialSubstitution(SS->SSK) {}
+
class CtorDtorName final : public Node {
const Node *Basename;
const bool IsDtor;
@@ -1666,13 +1660,14 @@ public:
void printDeclarator(OutputBuffer &OB) const {
if (!TemplateParams.empty()) {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
OB += "<";
TemplateParams.printWithComma(OB);
OB += ">";
}
- OB += "(";
+ OB.printOpen();
Params.printWithComma(OB);
- OB += ")";
+ OB.printClose();
}
void printLeft(OutputBuffer &OB) const override {
@@ -1692,9 +1687,9 @@ public:
template<typename Fn> void match(Fn F) const { F(Bindings); }
void printLeft(OutputBuffer &OB) const override {
- OB += '[';
+ OB.printOpen('[');
Bindings.printWithComma(OB);
- OB += ']';
+ OB.printClose(']');
}
};
@@ -1706,28 +1701,31 @@ class BinaryExpr : public Node {
const Node *RHS;
public:
- BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_)
- : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) {
- }
+ BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_,
+ Prec Prec_)
+ : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_),
+ RHS(RHS_) {}
- template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); }
+ template <typename Fn> void match(Fn F) const {
+ F(LHS, InfixOperator, RHS, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- // might be a template argument expression, then we need to disambiguate
- // with parens.
- if (InfixOperator == ">")
- OB += "(";
-
- OB += "(";
- LHS->print(OB);
- OB += ") ";
+ bool ParenAll = OB.isGtInsideTemplateArgs() &&
+ (InfixOperator == ">" || InfixOperator == ">>");
+ if (ParenAll)
+ OB.printOpen();
+ // Assignment is right associative, with special LHS precedence.
+ bool IsAssign = getPrecedence() == Prec::Assign;
+ LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign);
+ // No space before comma operator
+ if (!(InfixOperator == ","))
+ OB += " ";
OB += InfixOperator;
- OB += " (";
- RHS->print(OB);
- OB += ")";
-
- if (InfixOperator == ">")
- OB += ")";
+ OB += " ";
+ RHS->printAsOperand(OB, getPrecedence(), IsAssign);
+ if (ParenAll)
+ OB.printClose();
}
};
@@ -1736,17 +1734,18 @@ class ArraySubscriptExpr : public Node {
const Node *Op2;
public:
- ArraySubscriptExpr(const Node *Op1_, const Node *Op2_)
- : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {}
+ ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_)
+ : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {}
- template<typename Fn> void match(Fn F) const { F(Op1, Op2); }
+ template <typename Fn> void match(Fn F) const {
+ F(Op1, Op2, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- OB += "(";
- Op1->print(OB);
- OB += ")[";
- Op2->print(OB);
- OB += "]";
+ Op1->printAsOperand(OB, getPrecedence());
+ OB.printOpen('[');
+ Op2->printAsOperand(OB);
+ OB.printClose(']');
}
};
@@ -1755,15 +1754,15 @@ class PostfixExpr : public Node {
const StringView Operator;
public:
- PostfixExpr(const Node *Child_, StringView Operator_)
- : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {}
+ PostfixExpr(const Node *Child_, StringView Operator_, Prec Prec_)
+ : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {}
- template<typename Fn> void match(Fn F) const { F(Child, Operator); }
+ template <typename Fn> void match(Fn F) const {
+ F(Child, Operator, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- OB += "(";
- Child->print(OB);
- OB += ")";
+ Child->printAsOperand(OB, getPrecedence(), true);
OB += Operator;
}
};
@@ -1774,19 +1773,20 @@ class ConditionalExpr : public Node {
const Node *Else;
public:
- ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_)
- : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {}
+ ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_,
+ Prec Prec_)
+ : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {}
- template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); }
+ template <typename Fn> void match(Fn F) const {
+ F(Cond, Then, Else, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- OB += "(";
- Cond->print(OB);
- OB += ") ? (";
- Then->print(OB);
- OB += ") : (";
- Else->print(OB);
- OB += ")";
+ Cond->printAsOperand(OB, getPrecedence());
+ OB += " ? ";
+ Then->printAsOperand(OB);
+ OB += " : ";
+ Else->printAsOperand(OB, Prec::Assign, true);
}
};
@@ -1796,15 +1796,17 @@ class MemberExpr : public Node {
const Node *RHS;
public:
- MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_)
- : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
+ MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_, Prec Prec_)
+ : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {}
- template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); }
+ template <typename Fn> void match(Fn F) const {
+ F(LHS, Kind, RHS, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- LHS->print(OB);
+ LHS->printAsOperand(OB, getPrecedence(), true);
OB += Kind;
- RHS->print(OB);
+ RHS->printAsOperand(OB, getPrecedence(), false);
}
};
@@ -1848,15 +1850,19 @@ class EnclosingExpr : public Node {
const StringView Postfix;
public:
- EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_)
- : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_),
- Postfix(Postfix_) {}
+ EnclosingExpr(StringView Prefix_, const Node *Infix_,
+ Prec Prec_ = Prec::Primary)
+ : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {}
- template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); }
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Infix, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
OB += Prefix;
+ OB.printOpen();
Infix->print(OB);
+ OB.printClose();
OB += Postfix;
}
};
@@ -1868,18 +1874,24 @@ class CastExpr : public Node {
const Node *From;
public:
- CastExpr(StringView CastKind_, const Node *To_, const Node *From_)
- : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {}
+ CastExpr(StringView CastKind_, const Node *To_, const Node *From_, Prec Prec_)
+ : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {}
- template<typename Fn> void match(Fn F) const { F(CastKind, To, From); }
+ template <typename Fn> void match(Fn F) const {
+ F(CastKind, To, From, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
OB += CastKind;
- OB += "<";
- To->printLeft(OB);
- OB += ">(";
- From->printLeft(OB);
- OB += ")";
+ {
+ ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
+ OB += "<";
+ To->printLeft(OB);
+ OB += ">";
+ }
+ OB.printOpen();
+ From->printAsOperand(OB);
+ OB.printClose();
}
};
@@ -1893,10 +1905,11 @@ public:
template<typename Fn> void match(Fn F) const { F(Pack); }
void printLeft(OutputBuffer &OB) const override {
- OB += "sizeof...(";
+ OB += "sizeof...";
+ OB.printOpen();
ParameterPackExpansion PPE(Pack);
PPE.printLeft(OB);
- OB += ")";
+ OB.printClose();
}
};
@@ -1905,16 +1918,18 @@ class CallExpr : public Node {
NodeArray Args;
public:
- CallExpr(const Node *Callee_, NodeArray Args_)
- : Node(KCallExpr), Callee(Callee_), Args(Args_) {}
+ CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_)
+ : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {}
- template<typename Fn> void match(Fn F) const { F(Callee, Args); }
+ template <typename Fn> void match(Fn F) const {
+ F(Callee, Args, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
Callee->print(OB);
- OB += "(";
+ OB.printOpen();
Args.printWithComma(OB);
- OB += ")";
+ OB.printClose();
}
};
@@ -1927,31 +1942,31 @@ class NewExpr : public Node {
bool IsArray; // new[] ?
public:
NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
- bool IsArray_)
- : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_),
- IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+ bool IsArray_, Prec Prec_)
+ : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_),
+ InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
template<typename Fn> void match(Fn F) const {
- F(ExprList, Type, InitList, IsGlobal, IsArray);
+ F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence());
}
void printLeft(OutputBuffer &OB) const override {
if (IsGlobal)
- OB += "::operator ";
+ OB += "::";
OB += "new";
if (IsArray)
OB += "[]";
- OB += ' ';
if (!ExprList.empty()) {
- OB += "(";
+ OB.printOpen();
ExprList.printWithComma(OB);
- OB += ")";
+ OB.printClose();
}
+ OB += " ";
Type->print(OB);
if (!InitList.empty()) {
- OB += "(";
+ OB.printOpen();
InitList.printWithComma(OB);
- OB += ")";
+ OB.printClose();
}
}
};
@@ -1962,17 +1977,21 @@ class DeleteExpr : public Node {
bool IsArray;
public:
- DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_)
- : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {}
+ DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_)
+ : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_),
+ IsArray(IsArray_) {}
- template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); }
+ template <typename Fn> void match(Fn F) const {
+ F(Op, IsGlobal, IsArray, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
if (IsGlobal)
OB += "::";
OB += "delete";
if (IsArray)
- OB += "[] ";
+ OB += "[]";
+ OB += ' ';
Op->print(OB);
}
};
@@ -1982,16 +2001,16 @@ class PrefixExpr : public Node {
Node *Child;
public:
- PrefixExpr(StringView Prefix_, Node *Child_)
- : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {}
+ PrefixExpr(StringView Prefix_, Node *Child_, Prec Prec_)
+ : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {}
- template<typename Fn> void match(Fn F) const { F(Prefix, Child); }
+ template <typename Fn> void match(Fn F) const {
+ F(Prefix, Child, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
OB += Prefix;
- OB += "(";
- Child->print(OB);
- OB += ")";
+ Child->printAsOperand(OB, getPrecedence());
}
};
@@ -2014,17 +2033,20 @@ class ConversionExpr : public Node {
NodeArray Expressions;
public:
- ConversionExpr(const Node *Type_, NodeArray Expressions_)
- : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {}
+ ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_)
+ : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {}
- template<typename Fn> void match(Fn F) const { F(Type, Expressions); }
+ template <typename Fn> void match(Fn F) const {
+ F(Type, Expressions, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- OB += "(";
+ OB.printOpen();
Type->print(OB);
- OB += ")(";
+ OB.printClose();
+ OB.printOpen();
Expressions.printWithComma(OB);
- OB += ")";
+ OB.printClose();
}
};
@@ -2035,18 +2057,21 @@ class PointerToMemberConversionExpr : public Node {
public:
PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
- StringView Offset_)
- : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_),
- Offset(Offset_) {}
+ StringView Offset_, Prec Prec_)
+ : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_),
+ SubExpr(SubExpr_), Offset(Offset_) {}
- template<typename Fn> void match(Fn F) const { F(Type, SubExpr, Offset); }
+ template <typename Fn> void match(Fn F) const {
+ F(Type, SubExpr, Offset, getPrecedence());
+ }
void printLeft(OutputBuffer &OB) const override {
- OB += "(";
+ OB.printOpen();
Type->print(OB);
- OB += ")(";
+ OB.printClose();
+ OB.printOpen();
SubExpr->print(OB);
- OB += ")";
+ OB.printClose();
}
};
@@ -2132,41 +2157,33 @@ public:
void printLeft(OutputBuffer &OB) const override {
auto PrintPack = [&] {
- OB += '(';
+ OB.printOpen();
ParameterPackExpansion(Pack).print(OB);
- OB += ')';
+ OB.printClose();
};
- OB += '(';
-
- if (IsLeftFold) {
- // init op ... op pack
- if (Init != nullptr) {
- Init->print(OB);
- OB += ' ';
- OB += OperatorName;
- OB += ' ';
- }
- // ... op pack
- OB += "... ";
- OB += OperatorName;
- OB += ' ';
- PrintPack();
- } else { // !IsLeftFold
- // pack op ...
- PrintPack();
- OB += ' ';
- OB += OperatorName;
- OB += " ...";
- // pack op ... op init
- if (Init != nullptr) {
- OB += ' ';
- OB += OperatorName;
- OB += ' ';
- Init->print(OB);
- }
+ OB.printOpen();
+ // Either '[init op ]... op pack' or 'pack op ...[ op init]'
+ // Refactored to '[(init|pack) op ]...[ op (pack|init)]'
+ // Fold expr operands are cast-expressions
+ if (!IsLeftFold || Init != nullptr) {
+ // '(init|pack) op '
+ if (IsLeftFold)
+ Init->printAsOperand(OB, Prec::Cast, true);
+ else
+ PrintPack();
+ OB << " " << OperatorName << " ";
+ }
+ OB << "...";
+ if (IsLeftFold || Init != nullptr) {
+ // ' op (init|pack)'
+ OB << " " << OperatorName << " ";
+ if (IsLeftFold)
+ PrintPack();
+ else
+ Init->printAsOperand(OB, Prec::Cast, true);
}
- OB += ')';
+ OB.printClose();
}
};
@@ -2240,9 +2257,9 @@ public:
template<typename Fn> void match(Fn F) const { F(Ty, Integer); }
void printLeft(OutputBuffer &OB) const override {
- OB << "(";
+ OB.printOpen();
Ty->print(OB);
- OB << ")";
+ OB.printClose();
if (Integer[0] == 'n')
OB << "-" << Integer.dropFront(1);
@@ -2263,13 +2280,13 @@ public:
void printLeft(OutputBuffer &OB) const override {
if (Type.size() > 3) {
- OB += "(";
+ OB.printOpen();
OB += Type;
- OB += ")";
+ OB.printClose();
}
if (Value[0] == 'n') {
- OB += "-";
+ OB += '-';
OB += Value.dropFront(1);
} else
OB += Value;
@@ -2345,24 +2362,22 @@ using LongDoubleLiteral = FloatLiteralImpl<long double>;
template<typename Fn>
void Node::visit(Fn F) const {
switch (K) {
-#define CASE(X) case K ## X: return F(static_cast<const X*>(this));
- FOR_EACH_NODE_KIND(CASE)
-#undef CASE
+#define NODE(X) \
+ case K##X: \
+ return F(static_cast<const X *>(this));
+#include "ItaniumNodes.def"
}
assert(0 && "unknown mangling node kind");
}
/// Determine the kind of a node from its type.
template<typename NodeT> struct NodeKind;
-#define SPECIALIZATION(X) \
- template<> struct NodeKind<X> { \
- static constexpr Node::Kind Kind = Node::K##X; \
- static constexpr const char *name() { return #X; } \
+#define NODE(X) \
+ template <> struct NodeKind<X> { \
+ static constexpr Node::Kind Kind = Node::K##X; \
+ static constexpr const char *name() { return #X; } \
};
-FOR_EACH_NODE_KIND(SPECIALIZATION)
-#undef SPECIALIZATION
-
-#undef FOR_EACH_NODE_KIND
+#include "ItaniumNodes.def"
template <typename Derived, typename Alloc> struct AbstractManglingParser {
const char *First;
@@ -2500,17 +2515,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
/// Parse the <expr> production.
Node *parseExpr();
- Node *parsePrefixExpr(StringView Kind);
- Node *parseBinaryExpr(StringView Kind);
+ Node *parsePrefixExpr(StringView Kind, Node::Prec Prec);
+ Node *parseBinaryExpr(StringView Kind, Node::Prec Prec);
Node *parseIntegerLiteral(StringView Lit);
Node *parseExprPrimary();
template <class Float> Node *parseFloatingLiteral();
Node *parseFunctionParam();
- Node *parseNewExpr();
Node *parseConversionExpr();
Node *parseBracedExpr();
Node *parseFoldExpr();
- Node *parsePointerToMemberConversionExpr();
+ Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
Node *parseSubobjectExpr();
/// Parse the <type> production.
@@ -2558,17 +2572,80 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseName(NameState *State = nullptr);
Node *parseLocalName(NameState *State);
Node *parseOperatorName(NameState *State);
- Node *parseUnqualifiedName(NameState *State);
+ bool parseModuleNameOpt(ModuleName *&Module);
+ Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module);
Node *parseUnnamedTypeName(NameState *State);
Node *parseSourceName(NameState *State);
- Node *parseUnscopedName(NameState *State);
+ Node *parseUnscopedName(NameState *State, bool *isSubstName);
Node *parseNestedName(NameState *State);
Node *parseCtorDtorName(Node *&SoFar, NameState *State);
Node *parseAbiTags(Node *N);
+ struct OperatorInfo {
+ enum OIKind : unsigned char {
+ Prefix, // Prefix unary: @ expr
+ Postfix, // Postfix unary: expr @
+ Binary, // Binary: lhs @ rhs
+ Array, // Array index: lhs [ rhs ]
+ Member, // Member access: lhs @ rhs
+ New, // New
+ Del, // Delete
+ Call, // Function call: expr (expr*)
+ CCast, // C cast: (type)expr
+ Conditional, // Conditional: expr ? expr : expr
+ NameOnly, // Overload only, not allowed in expression.
+ // Below do not have operator names
+ NamedCast, // Named cast, @<type>(expr)
+ OfIdOp, // alignof, sizeof, typeid
+
+ Unnameable = NamedCast,
+ };
+ char Enc[2]; // Encoding
+ OIKind Kind; // Kind of operator
+ bool Flag : 1; // Entry-specific flag
+ Node::Prec Prec : 7; // Precedence
+ const char *Name; // Spelling
+
+ public:
+ constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P,
+ const char *N)
+ : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {}
+
+ public:
+ bool operator<(const OperatorInfo &Other) const {
+ return *this < Other.Enc;
+ }
+ bool operator<(const char *Peek) const {
+ return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]);
+ }
+ bool operator==(const char *Peek) const {
+ return Enc[0] == Peek[0] && Enc[1] == Peek[1];
+ }
+ bool operator!=(const char *Peek) const { return !this->operator==(Peek); }
+
+ public:
+ StringView getSymbol() const {
+ StringView Res = Name;
+ if (Kind < Unnameable) {
+ assert(Res.startsWith("operator") &&
+ "operator name does not start with 'operator'");
+ Res = Res.dropFront(sizeof("operator") - 1);
+ Res.consumeFront(' ');
+ }
+ return Res;
+ }
+ StringView getName() const { return Name; }
+ OIKind getKind() const { return Kind; }
+ bool getFlag() const { return Flag; }
+ Node::Prec getPrecedence() const { return Prec; }
+ };
+ static const OperatorInfo Ops[];
+ static const size_t NumOps;
+ const OperatorInfo *parseOperatorEncoding();
+
/// Parse the <unresolved-name> production.
- Node *parseUnresolvedName();
+ Node *parseUnresolvedName(bool Global);
Node *parseSimpleId();
Node *parseBaseUnresolvedName();
Node *parseUnresolvedType();
@@ -2589,26 +2666,16 @@ const char* parse_discriminator(const char* first, const char* last);
// ::= <substitution>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) {
- consumeIf('L'); // extension
-
if (look() == 'N')
return getDerived().parseNestedName(State);
if (look() == 'Z')
return getDerived().parseLocalName(State);
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)
+ bool IsSubst = false;
+
+ Result = getDerived().parseUnscopedName(State, &IsSubst);
+ if (!Result)
return nullptr;
if (look() == 'I') {
@@ -2668,38 +2735,63 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
+// [*] extension
template <typename Derived, typename Alloc>
Node *
-AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) {
- bool IsStd = consumeIf("St");
- if (IsStd)
- consumeIf('L');
+AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
+ bool *IsSubst) {
- Node *Result = getDerived().parseUnqualifiedName(State);
- if (Result == nullptr)
- return nullptr;
- if (IsStd)
- Result = make<StdQualifiedName>(Result);
+ Node *Std = nullptr;
+ if (consumeIf("St")) {
+ Std = make<NameType>("std");
+ if (Std == nullptr)
+ return nullptr;
+ }
- return Result;
+ Node *Res = nullptr;
+ ModuleName *Module = nullptr;
+ if (look() == 'S') {
+ Node *S = getDerived().parseSubstitution();
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName)
+ Module = static_cast<ModuleName *>(S);
+ else if (IsSubst && Std == nullptr) {
+ Res = S;
+ *IsSubst = true;
+ } else {
+ return nullptr;
+ }
+ }
+
+ if (Res == nullptr || Std != nullptr) {
+ Res = getDerived().parseUnqualifiedName(State, Std, Module);
+ }
+
+ return Res;
}
-// <unqualified-name> ::= <operator-name> [abi-tags]
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
-// ::= DC <source-name>+ E # structured binding declaration
+// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
+// ::= [<module-name>] L? <source-name> [<abi-tags>]
+// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
+// # structured binding declaration
+// ::= [<module-name>] L? DC <source-name>+ E
template <typename Derived, typename Alloc>
-Node *
-AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
- // <ctor-dtor-name>s are special-cased in parseNestedName().
+Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
+ NameState *State, Node *Scope, ModuleName *Module) {
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+
+ consumeIf('L');
+
Node *Result;
- if (look() == 'U')
- Result = getDerived().parseUnnamedTypeName(State);
- else if (look() >= '1' && look() <= '9')
+ if (look() >= '1' && look() <= '9') {
Result = getDerived().parseSourceName(State);
- else if (consumeIf("DC")) {
+ } else if (look() == 'U') {
+ Result = getDerived().parseUnnamedTypeName(State);
+ } else if (consumeIf("DC")) {
+ // Structured binding
size_t BindingsBegin = Names.size();
do {
Node *Binding = getDerived().parseSourceName(State);
@@ -2708,13 +2800,46 @@ AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) {
Names.push_back(Binding);
} while (!consumeIf('E'));
Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
- } else
+ } else if (look() == 'C' || look() == 'D') {
+ // A <ctor-dtor-name>.
+ if (Scope == nullptr || Module != nullptr)
+ return nullptr;
+ Result = getDerived().parseCtorDtorName(Scope, State);
+ } else {
Result = getDerived().parseOperatorName(State);
+ }
+
+ if (Result != nullptr && Module != nullptr)
+ Result = make<ModuleEntity>(Module, Result);
if (Result != nullptr)
Result = getDerived().parseAbiTags(Result);
+ if (Result != nullptr && Scope != nullptr)
+ Result = make<NestedName>(Scope, Result);
+
return Result;
}
+// <module-name> ::= <module-subname>
+// ::= <module-name> <module-subname>
+// ::= <substitution> # passed in by caller
+// <module-subname> ::= W <source-name>
+// ::= W P <source-name>
+template <typename Derived, typename Alloc>
+bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
+ ModuleName *&Module) {
+ while (consumeIf('W')) {
+ bool IsPartition = consumeIf('P');
+ Node *Sub = getDerived().parseSourceName(nullptr);
+ if (!Sub)
+ return true;
+ Module =
+ static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition));
+ Subs.push_back(Module);
+ }
+
+ return false;
+}
+
// <unnamed-type-name> ::= Ut [<nonnegative number>] _
// ::= <closure-type-name>
//
@@ -2736,7 +2861,7 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
return make<UnnamedTypeName>(Count);
}
if (consumeIf("Ul")) {
- SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel,
+ ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel,
TemplateParams.size());
ScopedTemplateParamList LambdaTemplateParams(this);
@@ -2814,97 +2939,131 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return make<NameType>(Name);
}
-// <operator-name> ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
+// Operator encodings
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<
+ Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
+ Alloc>::Ops[] = {
+ // Keep ordered by encoding
+ {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
+ {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
+ {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
+ {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
+ {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
+ {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
+ {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
+ "operator co_await"},
+ {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
+ {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
+ {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
+ {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
+ {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
+ {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
+ {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
+ {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
+ "operator delete[]"},
+ {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
+ {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
+ {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
+ "operator delete"},
+ {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator.*"},
+ {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix,
+ "operator."},
+ {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"},
+ {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="},
+ {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"},
+ {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="},
+ {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="},
+ {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"},
+ {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"},
+ {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="},
+ {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="},
+ {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"},
+ {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"},
+ {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="},
+ {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="},
+ {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"},
+ {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator*"},
+ {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"},
+ {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary,
+ "operator new[]"},
+ {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
+ {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
+ {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
+ {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
+ {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
+ {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
+ {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
+ {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="},
+ {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"},
+ {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem,
+ "operator->*"},
+ {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"},
+ {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"},
+ {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix,
+ "operator->"},
+ {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional,
+ "operator?"},
+ {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="},
+ {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="},
+ {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix,
+ "reinterpret_cast"},
+ {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
+ "operator%"},
+ {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
+ {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
+ {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
+ {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
+ {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
+ {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
+ "typeid "},
+ {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
+};
+template <typename Derived, typename Alloc>
+const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
+ sizeof(Ops[0]);
+
+// If the next 2 chars are an operator encoding, consume them and return their
+// OperatorInfo. Otherwise return nullptr.
+template <typename Derived, typename Alloc>
+const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
+AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
+ if (numLeft() < 2)
+ return nullptr;
+
+ // We can't use lower_bound as that can link to symbols in the C++ library,
+ // and this must remain independant of that.
+ size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds.
+ while (upper != lower) {
+ size_t middle = (upper + lower) / 2;
+ if (Ops[middle] < First)
+ lower = middle + 1;
+ else
+ upper = middle;
+ }
+ if (Ops[lower] != First)
+ return nullptr;
+
+ First += 2;
+ return &Ops[lower];
+}
+
+// <operator-name> ::= See parseOperatorEncoding()
// ::= li <source-name> # operator ""
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= ss # <=> C++2a
-// ::= v <digit> <source-name> # vendor extended operator
+// ::= v <digit> <source-name> # vendor extended operator
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
- switch (look()) {
- case 'a':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator&&");
- case 'd':
- case 'n':
- First += 2;
- return make<NameType>("operator&");
- case 'N':
- First += 2;
- return make<NameType>("operator&=");
- case 'S':
- First += 2;
- return make<NameType>("operator=");
- }
- return nullptr;
- case 'c':
- switch (look(1)) {
- case 'l':
- First += 2;
- return make<NameType>("operator()");
- case 'm':
- First += 2;
- return make<NameType>("operator,");
- case 'o':
- First += 2;
- return make<NameType>("operator~");
- // ::= cv <type> # (cast)
- case 'v': {
- First += 2;
- SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+ if (const auto *Op = parseOperatorEncoding()) {
+ if (Op->getKind() == OperatorInfo::CCast) {
+ // ::= cv <type> # (cast)
+ ScopedOverride<bool> SaveTemplate(TryToParseTemplateArgs, false);
// If we're parsing an encoding, State != nullptr and the conversion
// operators' <type> could have a <template-param> that refers to some
// <template-arg>s further ahead in the mangled name.
- SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
+ ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences,
PermitForwardTemplateReferences ||
State != nullptr);
Node *Ty = getDerived().parseType();
@@ -2913,185 +3072,29 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
if (State) State->CtorDtorConversion = true;
return make<ConversionOperatorType>(Ty);
}
- }
- return nullptr;
- case 'd':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator delete[]");
- case 'e':
- First += 2;
- return make<NameType>("operator*");
- case 'l':
- First += 2;
- return make<NameType>("operator delete");
- case 'v':
- First += 2;
- return make<NameType>("operator/");
- case 'V':
- First += 2;
- return make<NameType>("operator/=");
- }
- return nullptr;
- case 'e':
- switch (look(1)) {
- case 'o':
- First += 2;
- return make<NameType>("operator^");
- case 'O':
- First += 2;
- return make<NameType>("operator^=");
- case 'q':
- First += 2;
- return make<NameType>("operator==");
- }
- return nullptr;
- case 'g':
- switch (look(1)) {
- case 'e':
- First += 2;
- return make<NameType>("operator>=");
- case 't':
- First += 2;
- return make<NameType>("operator>");
- }
- return nullptr;
- case 'i':
- if (look(1) == 'x') {
- First += 2;
- return make<NameType>("operator[]");
- }
- return nullptr;
- case 'l':
- switch (look(1)) {
- case 'e':
- First += 2;
- return make<NameType>("operator<=");
+
+ if (Op->getKind() >= OperatorInfo::Unnameable)
+ /* Not a nameable operator. */
+ return nullptr;
+ if (Op->getKind() == OperatorInfo::Member && !Op->getFlag())
+ /* Not a nameable MemberExpr */
+ return nullptr;
+
+ return make<NameType>(Op->getName());
+ }
+
+ if (consumeIf("li")) {
// ::= li <source-name> # operator ""
- case 'i': {
- First += 2;
- Node *SN = getDerived().parseSourceName(State);
- if (SN == nullptr)
- return nullptr;
- return make<LiteralOperator>(SN);
- }
- case 's':
- First += 2;
- return make<NameType>("operator<<");
- case 'S':
- First += 2;
- return make<NameType>("operator<<=");
- case 't':
- First += 2;
- return make<NameType>("operator<");
- }
- return nullptr;
- case 'm':
- switch (look(1)) {
- case 'i':
- First += 2;
- return make<NameType>("operator-");
- case 'I':
- First += 2;
- return make<NameType>("operator-=");
- case 'l':
- First += 2;
- return make<NameType>("operator*");
- case 'L':
- First += 2;
- return make<NameType>("operator*=");
- case 'm':
- First += 2;
- return make<NameType>("operator--");
- }
- return nullptr;
- case 'n':
- switch (look(1)) {
- case 'a':
- First += 2;
- return make<NameType>("operator new[]");
- case 'e':
- First += 2;
- return make<NameType>("operator!=");
- case 'g':
- First += 2;
- return make<NameType>("operator-");
- case 't':
- First += 2;
- return make<NameType>("operator!");
- case 'w':
- First += 2;
- return make<NameType>("operator new");
- }
- return nullptr;
- case 'o':
- switch (look(1)) {
- case 'o':
- First += 2;
- return make<NameType>("operator||");
- case 'r':
- First += 2;
- return make<NameType>("operator|");
- case 'R':
- First += 2;
- return make<NameType>("operator|=");
- }
- return nullptr;
- case 'p':
- switch (look(1)) {
- case 'm':
- First += 2;
- return make<NameType>("operator->*");
- case 'l':
- First += 2;
- return make<NameType>("operator+");
- case 'L':
- First += 2;
- return make<NameType>("operator+=");
- case 'p':
- First += 2;
- return make<NameType>("operator++");
- case 's':
- First += 2;
- return make<NameType>("operator+");
- case 't':
- First += 2;
- return make<NameType>("operator->");
- }
- return nullptr;
- case 'q':
- if (look(1) == 'u') {
- First += 2;
- return make<NameType>("operator?");
- }
- return nullptr;
- case 'r':
- switch (look(1)) {
- case 'm':
- First += 2;
- return make<NameType>("operator%");
- case 'M':
- First += 2;
- return make<NameType>("operator%=");
- case 's':
- First += 2;
- return make<NameType>("operator>>");
- case 'S':
- First += 2;
- return make<NameType>("operator>>=");
- }
- return nullptr;
- case 's':
- if (look(1) == 's') {
- First += 2;
- return make<NameType>("operator<=>");
- }
- return nullptr;
- // ::= v <digit> <source-name> # vendor extended operator
- case 'v':
- if (std::isdigit(look(1))) {
- First += 2;
+ Node *SN = getDerived().parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<LiteralOperator>(SN);
+ }
+
+ if (consumeIf('v')) {
+ // ::= v <digit> <source-name> # vendor extended operator
+ if (look() >= '0' && look() <= '9') {
+ First++;
Node *SN = getDerived().parseSourceName(State);
if (SN == nullptr)
return nullptr;
@@ -3099,6 +3102,7 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) {
}
return nullptr;
}
+
return nullptr;
}
@@ -3117,19 +3121,11 @@ Node *
AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
NameState *State) {
if (SoFar->getKind() == Node::KSpecialSubstitution) {
- auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
- switch (SSK) {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- SoFar = make<ExpandedSpecialSubstitution>(SSK);
- if (!SoFar)
- return nullptr;
- break;
- default:
- break;
- }
+ // Expand the special substitution.
+ SoFar = make<ExpandedSpecialSubstitution>(
+ static_cast<SpecialSubstitution *>(SoFar));
+ if (!SoFar)
+ return nullptr;
}
if (consumeIf('C')) {
@@ -3158,8 +3154,10 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
return nullptr;
}
-// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix>
+// <unqualified-name> E
+// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix>
+// <template-args> E
//
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
@@ -3168,7 +3166,7 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar,
// ::= # empty
// ::= <substitution>
// ::= <prefix> <data-member-prefix>
-// extension ::= L
+// [*] extension
//
// <data-member-prefix> := <member source-name> [<template-args>] M
//
@@ -3188,90 +3186,76 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
if (State) State->ReferenceQualifier = FrefQualRValue;
} else if (consumeIf('R')) {
if (State) State->ReferenceQualifier = FrefQualLValue;
- } else
+ } else {
if (State) State->ReferenceQualifier = FrefQualNone;
-
- Node *SoFar = nullptr;
- auto PushComponent = [&](Node *Comp) {
- if (!Comp) return false;
- if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
- else SoFar = Comp;
- if (State) State->EndsWithTemplateArgs = false;
- return SoFar != nullptr;
- };
-
- if (consumeIf("St")) {
- SoFar = make<NameType>("std");
- if (!SoFar)
- return nullptr;
}
+ Node *SoFar = nullptr;
while (!consumeIf('E')) {
- consumeIf('L'); // extension
-
- // <data-member-prefix> := <member source-name> [<template-args>] M
- if (consumeIf('M')) {
- if (SoFar == nullptr)
- return nullptr;
- continue;
- }
+ if (State)
+ // Only set end-with-template on the case that does that.
+ State->EndsWithTemplateArgs = false;
- // ::= <template-param>
if (look() == 'T') {
- if (!PushComponent(getDerived().parseTemplateParam()))
- return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <template-prefix> <template-args>
- if (look() == 'I') {
+ // ::= <template-param>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseTemplateParam();
+ } else if (look() == 'I') {
+ // ::= <template-prefix> <template-args>
+ if (SoFar == nullptr)
+ return nullptr; // Must have a prefix.
Node *TA = getDerived().parseTemplateArgs(State != nullptr);
- if (TA == nullptr || SoFar == nullptr)
- return nullptr;
- SoFar = make<NameWithTemplateArgs>(SoFar, TA);
- if (!SoFar)
+ if (TA == nullptr)
return nullptr;
- if (State) State->EndsWithTemplateArgs = true;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <decltype>
- if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
- if (!PushComponent(getDerived().parseDecltype()))
+ if (SoFar->getKind() == Node::KNameWithTemplateArgs)
+ // Semantically <template-args> <template-args> cannot be generated by a
+ // C++ entity. There will always be [something like] a name between
+ // them.
return nullptr;
- Subs.push_back(SoFar);
- continue;
- }
-
- // ::= <substitution>
- if (look() == 'S' && look(1) != 't') {
- Node *S = getDerived().parseSubstitution();
- if (!PushComponent(S))
- return nullptr;
- if (SoFar != S)
- Subs.push_back(S);
- continue;
- }
+ if (State)
+ State->EndsWithTemplateArgs = true;
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+ // ::= <decltype>
+ if (SoFar != nullptr)
+ return nullptr; // Cannot have a prefix.
+ SoFar = getDerived().parseDecltype();
+ } else {
+ ModuleName *Module = nullptr;
+
+ if (look() == 'S') {
+ // ::= <substitution>
+ Node *S = nullptr;
+ if (look(1) == 't') {
+ First += 2;
+ S = make<NameType>("std");
+ } else {
+ S = getDerived().parseSubstitution();
+ }
+ if (!S)
+ return nullptr;
+ if (S->getKind() == Node::KModuleName) {
+ Module = static_cast<ModuleName *>(S);
+ } else if (SoFar != nullptr) {
+ return nullptr; // Cannot have a prefix.
+ } else {
+ SoFar = S;
+ continue; // Do not push a new substitution.
+ }
+ }
- // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
- if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
- if (SoFar == nullptr)
- return nullptr;
- if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State)))
- return nullptr;
- SoFar = getDerived().parseAbiTags(SoFar);
- if (SoFar == nullptr)
- return nullptr;
- Subs.push_back(SoFar);
- continue;
+ // ::= [<prefix>] <unqualified-name>
+ SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module);
}
- // ::= <prefix> <unqualified-name>
- if (!PushComponent(getDerived().parseUnqualifiedName(State)))
+ if (SoFar == nullptr)
return nullptr;
Subs.push_back(SoFar);
+
+ // No longer used.
+ // <data-member-prefix> := <member source-name> [<template-args>] M
+ consumeIf('M');
}
if (SoFar == nullptr || Subs.empty())
@@ -3366,6 +3350,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// [gs] has been parsed by caller.
// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
// # T::N::x /decltype(p)::N::x
@@ -3373,7 +3358,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() {
//
// <unresolved-qualifier-level> ::= <simple-id>
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
+Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) {
Node *SoFar = nullptr;
// srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
@@ -3407,8 +3392,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() {
return make<QualifiedName>(SoFar, Base);
}
- bool Global = consumeIf("gs");
-
// [gs] <base-unresolved-name> # x or (with "gs") ::x
if (!consumeIf("sr")) {
SoFar = getDerived().parseBaseUnresolvedName();
@@ -3638,7 +3621,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() {
return nullptr;
if (!consumeIf('E'))
return nullptr;
- return make<EnclosingExpr>("decltype(", E, ")");
+ return make<EnclosingExpr>("decltype", E);
}
// <array-type> ::= A <positive dimension number> _ <element type>
@@ -3724,8 +3707,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
StringView Proto;
{
- SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
- SaveLast(Last, ProtoSourceName.end());
+ ScopedOverride<const char *> SaveFirst(First, ProtoSourceName.begin()),
+ SaveLast(Last, ProtoSourceName.end());
Proto = parseBareSourceName();
}
if (Proto.empty())
@@ -3930,6 +3913,22 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
return nullptr;
return make<BinaryFPType>(DimensionNumber);
}
+ // ::= DB <number> _ # C23 signed _BitInt(N)
+ // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N)
+ // ::= DU <number> _ # C23 unsigned _BitInt(N)
+ // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N)
+ case 'B':
+ case 'U': {
+ bool Signed = look(1) == 'B';
+ First += 2;
+ Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber())
+ : getDerived().parseExpr();
+ if (!Size)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<BitIntType>(Size, Signed);
+ }
// ::= Di # char32_t
case 'i':
First += 2;
@@ -4078,8 +4077,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
// ::= <substitution> # See Compression below
case 'S': {
if (look(1) != 't') {
- Result = getDerived().parseSubstitution();
- if (Result == nullptr)
+ bool IsSubst = false;
+ Result = getDerived().parseUnscopedName(nullptr, &IsSubst);
+ if (!Result)
return nullptr;
// Sub could be either of:
@@ -4092,12 +4092,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
// If this is followed by some <template-args>, and we're permitted to
// parse them, take the second production.
- if (TryToParseTemplateArgs && look() == 'I') {
+ if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) {
+ if (!IsSubst)
+ Subs.push_back(Result);
Node *TA = getDerived().parseTemplateArgs();
if (TA == nullptr)
return nullptr;
Result = make<NameWithTemplateArgs>(Result, TA);
- } else {
+ } else if (IsSubst) {
// If all we parsed was a substitution, don't re-insert into the
// substitution table.
return Result;
@@ -4122,22 +4124,24 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
}
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) {
+Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind,
+ Node::Prec Prec) {
Node *E = getDerived().parseExpr();
if (E == nullptr)
return nullptr;
- return make<PrefixExpr>(Kind, E);
+ return make<PrefixExpr>(Kind, E, Prec);
}
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) {
+Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind,
+ Node::Prec Prec) {
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
- return make<BinaryExpr>(LHS, Kind, RHS);
+ return make<BinaryExpr>(LHS, Kind, RHS, Prec);
}
template <typename Derived, typename Alloc>
@@ -4192,43 +4196,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() {
return nullptr;
}
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
-template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() {
- bool Global = consumeIf("gs");
- bool IsArray = look(1) == 'a';
- if (!consumeIf("nw") && !consumeIf("na"))
- return nullptr;
- size_t Exprs = Names.size();
- while (!consumeIf('_')) {
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return nullptr;
- Names.push_back(Ex);
- }
- NodeArray ExprList = popTrailingNodeArray(Exprs);
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
- if (consumeIf("pi")) {
- size_t InitsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *Init = getDerived().parseExpr();
- if (Init == nullptr)
- return Init;
- Names.push_back(Init);
- }
- NodeArray Inits = popTrailingNodeArray(InitsBegin);
- return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
- } else if (!consumeIf('E'))
- return nullptr;
- return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
-}
-
// cv <type> <expression> # conversion with one argument
// cv <type> _ <expression>* E # conversion with a different number of arguments
template <typename Derived, typename Alloc>
@@ -4237,7 +4204,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() {
return nullptr;
Node *Ty;
{
- SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+ ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
Ty = getDerived().parseType();
}
@@ -4354,7 +4321,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() {
return nullptr;
}
case 'D':
- if (consumeIf("DnE"))
+ if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E')))
return make<NameType>("nullptr");
return nullptr;
case 'T':
@@ -4441,55 +4408,38 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (!consumeIf('f'))
return nullptr;
- char FoldKind = look();
- bool IsLeftFold, HasInitializer;
- HasInitializer = FoldKind == 'L' || FoldKind == 'R';
- if (FoldKind == 'l' || FoldKind == 'L')
- IsLeftFold = true;
- else if (FoldKind == 'r' || FoldKind == 'R')
- IsLeftFold = false;
- else
+ bool IsLeftFold = false, HasInitializer = false;
+ switch (look()) {
+ default:
return nullptr;
+ case 'L':
+ IsLeftFold = true;
+ HasInitializer = true;
+ break;
+ case 'R':
+ HasInitializer = true;
+ break;
+ case 'l':
+ IsLeftFold = true;
+ break;
+ case 'r':
+ break;
+ }
++First;
- // FIXME: This map is duplicated in parseOperatorName and parseExpr.
- StringView OperatorName;
- if (consumeIf("aa")) OperatorName = "&&";
- else if (consumeIf("an")) OperatorName = "&";
- else if (consumeIf("aN")) OperatorName = "&=";
- else if (consumeIf("aS")) OperatorName = "=";
- else if (consumeIf("cm")) OperatorName = ",";
- else if (consumeIf("ds")) OperatorName = ".*";
- else if (consumeIf("dv")) OperatorName = "/";
- else if (consumeIf("dV")) OperatorName = "/=";
- else if (consumeIf("eo")) OperatorName = "^";
- else if (consumeIf("eO")) OperatorName = "^=";
- else if (consumeIf("eq")) OperatorName = "==";
- else if (consumeIf("ge")) OperatorName = ">=";
- else if (consumeIf("gt")) OperatorName = ">";
- else if (consumeIf("le")) OperatorName = "<=";
- else if (consumeIf("ls")) OperatorName = "<<";
- else if (consumeIf("lS")) OperatorName = "<<=";
- else if (consumeIf("lt")) OperatorName = "<";
- else if (consumeIf("mi")) OperatorName = "-";
- else if (consumeIf("mI")) OperatorName = "-=";
- else if (consumeIf("ml")) OperatorName = "*";
- else if (consumeIf("mL")) OperatorName = "*=";
- else if (consumeIf("ne")) OperatorName = "!=";
- else if (consumeIf("oo")) OperatorName = "||";
- else if (consumeIf("or")) OperatorName = "|";
- else if (consumeIf("oR")) OperatorName = "|=";
- else if (consumeIf("pl")) OperatorName = "+";
- else if (consumeIf("pL")) OperatorName = "+=";
- else if (consumeIf("rm")) OperatorName = "%";
- else if (consumeIf("rM")) OperatorName = "%=";
- else if (consumeIf("rs")) OperatorName = ">>";
- else if (consumeIf("rS")) OperatorName = ">>=";
- else return nullptr;
-
- Node *Pack = getDerived().parseExpr(), *Init = nullptr;
+ const auto *Op = parseOperatorEncoding();
+ if (!Op)
+ return nullptr;
+ if (!(Op->getKind() == OperatorInfo::Binary
+ || (Op->getKind() == OperatorInfo::Member
+ && Op->getName().back() == '*')))
+ return nullptr;
+
+ Node *Pack = getDerived().parseExpr();
if (Pack == nullptr)
return nullptr;
+
+ Node *Init = nullptr;
if (HasInitializer) {
Init = getDerived().parseExpr();
if (Init == nullptr)
@@ -4499,14 +4449,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
if (IsLeftFold && Init)
std::swap(Pack, Init);
- return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
+ return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init);
}
// <expression> ::= mc <parameter type> <expr> [<offset number>] E
//
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr() {
+Node *
+AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr(
+ Node::Prec Prec) {
Node *Ty = getDerived().parseType();
if (!Ty)
return nullptr;
@@ -4516,7 +4468,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr
StringView Offset = getDerived().parseNumber(true);
if (!consumeIf('E'))
return nullptr;
- return make<PointerToMemberConversionExpr>(Ty, Expr, Offset);
+ return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec);
}
// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
@@ -4593,316 +4545,127 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
bool Global = consumeIf("gs");
- if (numLeft() < 2)
- return nullptr;
- switch (*First) {
- case 'L':
- return getDerived().parseExprPrimary();
- case 'T':
- return getDerived().parseTemplateParam();
- case 'f': {
- // Disambiguate a fold expression from a <function-param>.
- if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
- return getDerived().parseFunctionParam();
- return getDerived().parseFoldExpr();
- }
- case 'a':
- switch (First[1]) {
- case 'a':
- First += 2;
- return getDerived().parseBinaryExpr("&&");
- case 'd':
- First += 2;
- return getDerived().parsePrefixExpr("&");
- case 'n':
- First += 2;
- return getDerived().parseBinaryExpr("&");
- case 'N':
- First += 2;
- return getDerived().parseBinaryExpr("&=");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr("=");
- case 't': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- case 'z': {
- First += 2;
- Node *Ty = getDerived().parseExpr();
- if (Ty == nullptr)
- return nullptr;
- return make<EnclosingExpr>("alignof (", Ty, ")");
- }
- }
- return nullptr;
- case 'c':
- switch (First[1]) {
- // cc <type> <expression> # const_cast<type>(expression)
- case 'c': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("const_cast", Ty, Ex);
- }
- // cl <expression>+ E # call
- case 'l': {
- First += 2;
- Node *Callee = getDerived().parseExpr();
- if (Callee == nullptr)
- return Callee;
- size_t ExprsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = getDerived().parseExpr();
- if (E == nullptr)
- return E;
- Names.push_back(E);
- }
- return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
- }
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr(",");
- case 'o':
- First += 2;
- return getDerived().parsePrefixExpr("~");
- case 'v':
- return getDerived().parseConversionExpr();
- }
- return nullptr;
- case 'd':
- switch (First[1]) {
- case 'a': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
- }
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
+ const auto *Op = parseOperatorEncoding();
+ if (Op) {
+ auto Sym = Op->getSymbol();
+ switch (Op->getKind()) {
+ case OperatorInfo::Binary:
+ // Binary operator: lhs @ rhs
+ return getDerived().parseBinaryExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Prefix:
+ // Prefix unary operator: @ expr
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
+ case OperatorInfo::Postfix: {
+ // Postfix unary operator: expr @
+ if (consumeIf('_'))
+ return getDerived().parsePrefixExpr(Sym, Op->getPrecedence());
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("dynamic_cast", T, Ex);
- }
- case 'e':
- First += 2;
- return getDerived().parsePrefixExpr("*");
- case 'l': {
- First += 2;
- Node *E = getDerived().parseExpr();
- if (E == nullptr)
- return E;
- return make<DeleteExpr>(E, Global, /*is_array=*/false);
+ return nullptr;
+ return make<PostfixExpr>(Ex, Sym, Op->getPrecedence());
}
- case 'n':
- return getDerived().parseUnresolvedName();
- case 's': {
- First += 2;
- Node *LHS = getDerived().parseExpr();
- if (LHS == nullptr)
+ case OperatorInfo::Array: {
+ // Array Index: lhs [ rhs ]
+ Node *Base = getDerived().parseExpr();
+ if (Base == nullptr)
return nullptr;
- Node *RHS = getDerived().parseExpr();
- if (RHS == nullptr)
+ Node *Index = getDerived().parseExpr();
+ if (Index == nullptr)
return nullptr;
- return make<MemberExpr>(LHS, ".*", RHS);
+ return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence());
}
- case 't': {
- First += 2;
+ case OperatorInfo::Member: {
+ // Member access lhs @ rhs
Node *LHS = getDerived().parseExpr();
if (LHS == nullptr)
- return LHS;
+ return nullptr;
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
- return make<MemberExpr>(LHS, ".", RHS);
- }
- case 'v':
- First += 2;
- return getDerived().parseBinaryExpr("/");
- case 'V':
- First += 2;
- return getDerived().parseBinaryExpr("/=");
- }
- return nullptr;
- case 'e':
- switch (First[1]) {
- case 'o':
- First += 2;
- return getDerived().parseBinaryExpr("^");
- case 'O':
- First += 2;
- return getDerived().parseBinaryExpr("^=");
- case 'q':
- First += 2;
- return getDerived().parseBinaryExpr("==");
- }
- return nullptr;
- case 'g':
- switch (First[1]) {
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr(">=");
- case 't':
- First += 2;
- return getDerived().parseBinaryExpr(">");
- }
- return nullptr;
- case 'i':
- switch (First[1]) {
- case 'x': {
- First += 2;
- Node *Base = getDerived().parseExpr();
- if (Base == nullptr)
+ return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence());
+ }
+ case OperatorInfo::New: {
+ // New
+ // # new (expr-list) type [(init)]
+ // [gs] nw <expression>* _ <type> [pi <expression>*] E
+ // # new[] (expr-list) type [(init)]
+ // [gs] na <expression>* _ <type> [pi <expression>*] E
+ size_t Exprs = Names.size();
+ while (!consumeIf('_')) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ Names.push_back(Ex);
+ }
+ NodeArray ExprList = popTrailingNodeArray(Exprs);
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
return nullptr;
- Node *Index = getDerived().parseExpr();
- if (Index == nullptr)
- return Index;
- return make<ArraySubscriptExpr>(Base, Index);
- }
- case 'l': {
- First += 2;
+ bool HaveInits = consumeIf("pi");
size_t InitsBegin = Names.size();
while (!consumeIf('E')) {
- Node *E = getDerived().parseBracedExpr();
- if (E == nullptr)
+ if (!HaveInits)
return nullptr;
- Names.push_back(E);
+ Node *Init = getDerived().parseExpr();
+ if (Init == nullptr)
+ return Init;
+ Names.push_back(Init);
}
- return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
- }
+ NodeArray Inits = popTrailingNodeArray(InitsBegin);
+ return make<NewExpr>(ExprList, Ty, Inits, Global,
+ /*IsArray=*/Op->getFlag(), Op->getPrecedence());
}
- return nullptr;
- case 'l':
- switch (First[1]) {
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr("<=");
- case 's':
- First += 2;
- return getDerived().parseBinaryExpr("<<");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr("<<=");
- case 't':
- First += 2;
- return getDerived().parseBinaryExpr("<");
- }
- return nullptr;
- case 'm':
- switch (First[1]) {
- case 'c':
- First += 2;
- return parsePointerToMemberConversionExpr();
- case 'i':
- First += 2;
- return getDerived().parseBinaryExpr("-");
- case 'I':
- First += 2;
- return getDerived().parseBinaryExpr("-=");
- case 'l':
- First += 2;
- return getDerived().parseBinaryExpr("*");
- case 'L':
- First += 2;
- return getDerived().parseBinaryExpr("*=");
- case 'm':
- First += 2;
- if (consumeIf('_'))
- return getDerived().parsePrefixExpr("--");
+ case OperatorInfo::Del: {
+ // Delete
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
return nullptr;
- return make<PostfixExpr>(Ex, "--");
- }
- return nullptr;
- case 'n':
- switch (First[1]) {
- case 'a':
- case 'w':
- return getDerived().parseNewExpr();
- case 'e':
- First += 2;
- return getDerived().parseBinaryExpr("!=");
- case 'g':
- First += 2;
- return getDerived().parsePrefixExpr("-");
- case 't':
- First += 2;
- return getDerived().parsePrefixExpr("!");
- case 'x':
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("noexcept (", Ex, ")");
+ return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(),
+ Op->getPrecedence());
}
- return nullptr;
- case 'o':
- switch (First[1]) {
- case 'n':
- return getDerived().parseUnresolvedName();
- case 'o':
- First += 2;
- return getDerived().parseBinaryExpr("||");
- case 'r':
- First += 2;
- return getDerived().parseBinaryExpr("|");
- case 'R':
- First += 2;
- return getDerived().parseBinaryExpr("|=");
- }
- return nullptr;
- case 'p':
- switch (First[1]) {
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr("->*");
- case 'l':
- First += 2;
- return getDerived().parseBinaryExpr("+");
- case 'L':
- First += 2;
- return getDerived().parseBinaryExpr("+=");
- case 'p': {
- First += 2;
- if (consumeIf('_'))
- return getDerived().parsePrefixExpr("++");
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<PostfixExpr>(Ex, "++");
+ case OperatorInfo::Call: {
+ // Function Call
+ Node *Callee = getDerived().parseExpr();
+ if (Callee == nullptr)
+ return nullptr;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin),
+ Op->getPrecedence());
}
- case 's':
- First += 2;
- return getDerived().parsePrefixExpr("+");
- case 't': {
- First += 2;
- Node *L = getDerived().parseExpr();
- if (L == nullptr)
+ case OperatorInfo::CCast: {
+ // C Cast: (type)expr
+ Node *Ty;
+ {
+ ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = getDerived().parseType();
+ }
+ if (Ty == nullptr)
return nullptr;
- Node *R = getDerived().parseExpr();
- if (R == nullptr)
+
+ size_t ExprsBegin = Names.size();
+ bool IsMany = consumeIf('_');
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ if (!IsMany)
+ break;
+ }
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ if (!IsMany && Exprs.size() != 1)
return nullptr;
- return make<MemberExpr>(L, "->", R);
+ return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence());
}
- }
- return nullptr;
- case 'q':
- if (First[1] == 'u') {
- First += 2;
+ case OperatorInfo::Conditional: {
+ // Conditional operator: expr ? expr : expr
Node *Cond = getDerived().parseExpr();
if (Cond == nullptr)
return nullptr;
@@ -4912,147 +4675,120 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
Node *RHS = getDerived().parseExpr();
if (RHS == nullptr)
return nullptr;
- return make<ConditionalExpr>(Cond, LHS, RHS);
- }
- return nullptr;
- case 'r':
- switch (First[1]) {
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("reinterpret_cast", T, Ex);
+ return make<ConditionalExpr>(Cond, LHS, RHS, Op->getPrecedence());
}
- case 'm':
- First += 2;
- return getDerived().parseBinaryExpr("%");
- case 'M':
- First += 2;
- return getDerived().parseBinaryExpr("%=");
- case 's':
- First += 2;
- return getDerived().parseBinaryExpr(">>");
- case 'S':
- First += 2;
- return getDerived().parseBinaryExpr(">>=");
- }
- return nullptr;
- case 's':
- switch (First[1]) {
- case 'c': {
- First += 2;
- Node *T = getDerived().parseType();
- if (T == nullptr)
- return T;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<CastExpr>("static_cast", T, Ex);
- }
- case 'o':
- First += 2;
- return parseSubobjectExpr();
- case 'p': {
- First += 2;
- Node *Child = getDerived().parseExpr();
- if (Child == nullptr)
- return nullptr;
- return make<ParameterPackExpansion>(Child);
- }
- case 'r':
- return getDerived().parseUnresolvedName();
- case 't': {
- First += 2;
+ case OperatorInfo::NamedCast: {
+ // Named cast operation, @<type>(expr)
Node *Ty = getDerived().parseType();
if (Ty == nullptr)
- return Ty;
- return make<EnclosingExpr>("sizeof (", Ty, ")");
- }
- case 'z': {
- First += 2;
+ return nullptr;
Node *Ex = getDerived().parseExpr();
if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("sizeof (", Ex, ")");
+ return nullptr;
+ return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence());
}
- case 'Z':
- First += 2;
- if (look() == 'T') {
- Node *R = getDerived().parseTemplateParam();
- if (R == nullptr)
- return nullptr;
- return make<SizeofParamPackExpr>(R);
- } else if (look() == 'f') {
- Node *FP = getDerived().parseFunctionParam();
- if (FP == nullptr)
- return nullptr;
- return make<EnclosingExpr>("sizeof... (", FP, ")");
- }
- return nullptr;
- case 'P': {
- First += 2;
- size_t ArgsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *Arg = getDerived().parseTemplateArg();
- if (Arg == nullptr)
- return nullptr;
- Names.push_back(Arg);
- }
- auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
- if (!Pack)
+ case OperatorInfo::OfIdOp: {
+ // [sizeof/alignof/typeid] ( <type>|<expr> )
+ Node *Arg =
+ Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr();
+ if (!Arg)
return nullptr;
- return make<EnclosingExpr>("sizeof... (", Pack, ")");
+ return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence());
}
+ case OperatorInfo::NameOnly: {
+ // Not valid as an expression operand.
+ return nullptr;
}
- return nullptr;
- case 't':
- switch (First[1]) {
- case 'e': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
- return Ex;
- return make<EnclosingExpr>("typeid (", Ex, ")");
}
- case 'i': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
- return Ty;
- return make<EnclosingExpr>("typeid (", Ty, ")");
+ DEMANGLE_UNREACHABLE;
+ }
+
+ if (numLeft() < 2)
+ return nullptr;
+
+ if (look() == 'L')
+ return getDerived().parseExprPrimary();
+ if (look() == 'T')
+ return getDerived().parseTemplateParam();
+ if (look() == 'f') {
+ // Disambiguate a fold expression from a <function-param>.
+ if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
+ return getDerived().parseFunctionParam();
+ return getDerived().parseFoldExpr();
+ }
+ if (consumeIf("il")) {
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
}
- case 'l': {
- First += 2;
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
+ return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+ }
+ if (consumeIf("mc"))
+ return parsePointerToMemberConversionExpr(Node::Prec::Unary);
+ if (consumeIf("nx")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
+ }
+ if (consumeIf("so"))
+ return parseSubobjectExpr();
+ if (consumeIf("sp")) {
+ Node *Child = getDerived().parseExpr();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ParameterPackExpansion>(Child);
+ }
+ if (consumeIf("sZ")) {
+ if (look() == 'T') {
+ Node *R = getDerived().parseTemplateParam();
+ if (R == nullptr)
return nullptr;
- size_t InitsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = getDerived().parseBracedExpr();
- if (E == nullptr)
- return nullptr;
- Names.push_back(E);
- }
- return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+ return make<SizeofParamPackExpr>(R);
}
- case 'r':
- First += 2;
- return make<NameType>("throw");
- case 'w': {
- First += 2;
- Node *Ex = getDerived().parseExpr();
- if (Ex == nullptr)
+ Node *FP = getDerived().parseFunctionParam();
+ if (FP == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... ", FP);
+ }
+ if (consumeIf("sP")) {
+ size_t ArgsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Arg = getDerived().parseTemplateArg();
+ if (Arg == nullptr)
return nullptr;
- return make<ThrowExpr>(Ex);
+ Names.push_back(Arg);
}
+ auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
+ if (!Pack)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... ", Pack);
+ }
+ if (consumeIf("tl")) {
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
}
- return nullptr;
- case 'u': {
- ++First;
+ return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+ }
+ if (consumeIf("tr"))
+ return make<NameType>("throw");
+ if (consumeIf("tw")) {
+ Node *Ex = getDerived().parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<ThrowExpr>(Ex);
+ }
+ if (consumeIf('u')) {
Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr);
if (!Name)
return nullptr;
@@ -5061,45 +4797,36 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
// interpreted as <type> node 'short' or 'ellipsis'. However, neither
// __uuidof(short) nor __uuidof(...) can actually appear, so there is no
// actual conflict here.
+ bool IsUUID = false;
+ Node *UUID = nullptr;
if (Name->getBaseName() == "__uuidof") {
- if (numLeft() < 2)
- return nullptr;
- if (*First == 't') {
- ++First;
- Node *Ty = getDerived().parseType();
- if (!Ty)
- return nullptr;
- return make<CallExpr>(Name, makeNodeArray(&Ty, &Ty + 1));
- }
- if (*First == 'z') {
- ++First;
- Node *Ex = getDerived().parseExpr();
- if (!Ex)
- return nullptr;
- return make<CallExpr>(Name, makeNodeArray(&Ex, &Ex + 1));
+ if (consumeIf('t')) {
+ UUID = getDerived().parseType();
+ IsUUID = true;
+ } else if (consumeIf('z')) {
+ UUID = getDerived().parseExpr();
+ IsUUID = true;
}
}
size_t ExprsBegin = Names.size();
- while (!consumeIf('E')) {
- Node *E = getDerived().parseTemplateArg();
- if (E == nullptr)
- return E;
- Names.push_back(E);
+ if (IsUUID) {
+ if (UUID == nullptr)
+ return nullptr;
+ Names.push_back(UUID);
+ } else {
+ while (!consumeIf('E')) {
+ Node *E = getDerived().parseTemplateArg();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
}
- return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin));
- }
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return getDerived().parseUnresolvedName();
+ return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin),
+ Node::Prec::Postfix);
}
- return nullptr;
+
+ // Only unresolved names remain.
+ return getDerived().parseUnresolvedName(Global);
}
// <call-offset> ::= h <nv-offset> _
@@ -5132,14 +4859,17 @@ bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() {
// # second call-offset is result adjustment
// ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
-// ::= GV <object name> # Guard variable for one-time initialization
+// # Guard variable for one-time initialization
+// ::= GV <object name>
// # No <type>
// ::= TW <object name> # Thread-local wrapper
// ::= TH <object name> # Thread-local initialization
// ::= GR <object name> _ # First temporary
// ::= GR <object name> <seq-id> _ # Subsequent temporaries
-// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// # construction vtable for second-in-first
+// extension ::= TC <first type> <number> _ <second type>
// extension ::= GR <object name> # reference temporary for object
+// extension ::= GI <module name> # module global initializer
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
switch (look()) {
@@ -5266,6 +4996,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
return nullptr;
return make<SpecialName>("reference temporary for ", Name);
}
+ // GI <module-name> v
+ case 'I': {
+ First += 2;
+ ModuleName *Module = nullptr;
+ if (getDerived().parseModuleNameOpt(Module))
+ return nullptr;
+ if (Module == nullptr)
+ return nullptr;
+ return make<SpecialName>("initializer for module ", Module);
+ }
}
}
return nullptr;
@@ -5380,7 +5120,7 @@ template <>
struct FloatData<long double>
{
#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
- defined(__wasm__)
+ defined(__wasm__) || defined(__riscv) || defined(__loongarch__)
static const size_t mangled_size = 32;
#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
static const size_t mangled_size = 16;
@@ -5445,6 +5185,7 @@ bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) {
// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+// The St case is handled specially in parseNestedName.
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
if (!consumeIf('S'))
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumNodes.def b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumNodes.def
new file mode 100644
index 0000000000..f615cb9fad
--- /dev/null
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/ItaniumNodes.def
@@ -0,0 +1,95 @@
+//===------------------------- ItaniumNodes.def ----------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Define the demangler's node names
+
+#ifndef NODE
+#error Define NODE to handle nodes
+#endif
+
+NODE(NodeArrayNode)
+NODE(DotSuffix)
+NODE(VendorExtQualType)
+NODE(QualType)
+NODE(ConversionOperatorType)
+NODE(PostfixQualifiedType)
+NODE(ElaboratedTypeSpefType)
+NODE(NameType)
+NODE(AbiTagAttr)
+NODE(EnableIfAttr)
+NODE(ObjCProtoName)
+NODE(PointerType)
+NODE(ReferenceType)
+NODE(PointerToMemberType)
+NODE(ArrayType)
+NODE(FunctionType)
+NODE(NoexceptSpec)
+NODE(DynamicExceptionSpec)
+NODE(FunctionEncoding)
+NODE(LiteralOperator)
+NODE(SpecialName)
+NODE(CtorVtableSpecialName)
+NODE(QualifiedName)
+NODE(NestedName)
+NODE(LocalName)
+NODE(ModuleName)
+NODE(ModuleEntity)
+NODE(VectorType)
+NODE(PixelVectorType)
+NODE(BinaryFPType)
+NODE(BitIntType)
+NODE(SyntheticTemplateParamName)
+NODE(TypeTemplateParamDecl)
+NODE(NonTypeTemplateParamDecl)
+NODE(TemplateTemplateParamDecl)
+NODE(TemplateParamPackDecl)
+NODE(ParameterPack)
+NODE(TemplateArgumentPack)
+NODE(ParameterPackExpansion)
+NODE(TemplateArgs)
+NODE(ForwardTemplateReference)
+NODE(NameWithTemplateArgs)
+NODE(GlobalQualifiedName)
+NODE(ExpandedSpecialSubstitution)
+NODE(SpecialSubstitution)
+NODE(CtorDtorName)
+NODE(DtorName)
+NODE(UnnamedTypeName)
+NODE(ClosureTypeName)
+NODE(StructuredBindingName)
+NODE(BinaryExpr)
+NODE(ArraySubscriptExpr)
+NODE(PostfixExpr)
+NODE(ConditionalExpr)
+NODE(MemberExpr)
+NODE(SubobjectExpr)
+NODE(EnclosingExpr)
+NODE(CastExpr)
+NODE(SizeofParamPackExpr)
+NODE(CallExpr)
+NODE(NewExpr)
+NODE(DeleteExpr)
+NODE(PrefixExpr)
+NODE(FunctionParam)
+NODE(ConversionExpr)
+NODE(PointerToMemberConversionExpr)
+NODE(InitListExpr)
+NODE(FoldExpr)
+NODE(ThrowExpr)
+NODE(BoolExpr)
+NODE(StringLiteral)
+NODE(LambdaExpr)
+NODE(EnumLiteral)
+NODE(IntegerLiteral)
+NODE(FloatLiteral)
+NODE(DoubleLiteral)
+NODE(LongDoubleLiteral)
+NODE(BracedExpr)
+NODE(BracedRangeExpr)
+
+#undef NODE
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h b/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
index 3b27328522..c9b211b544 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
+++ b/contrib/libs/cxxsupp/libcxxabi/src/demangle/Utility.h
@@ -33,61 +33,78 @@ class OutputBuffer {
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
- // Ensure there is at least n more positions in buffer.
+ // Ensure there are at least N more positions in the buffer.
void grow(size_t N) {
- if (N + CurrentPosition >= BufferCapacity) {
+ size_t Need = N + CurrentPosition;
+ if (Need > BufferCapacity) {
+ // Reduce the number of reallocations, with a bit of hysteresis. The
+ // number here is chosen so the first allocation will more-than-likely not
+ // allocate more than 1K.
+ Need += 1024 - 32;
BufferCapacity *= 2;
- if (BufferCapacity < N + CurrentPosition)
- BufferCapacity = N + CurrentPosition;
+ if (BufferCapacity < Need)
+ BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
- void writeUnsigned(uint64_t N, bool isNeg = false) {
- // Handle special case...
- if (N == 0) {
- *this << '0';
- return;
- }
-
+ OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
std::array<char, 21> Temp;
char *TempPtr = Temp.data() + Temp.size();
- while (N) {
+ // Output at least one character.
+ do {
*--TempPtr = char('0' + N % 10);
N /= 10;
- }
+ } while (N);
- // Add negative sign...
+ // Add negative sign.
if (isNeg)
*--TempPtr = '-';
- this->operator<<(StringView(TempPtr, Temp.data() + Temp.size()));
+
+ return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
}
public:
OutputBuffer(char *StartBuf, size_t Size)
- : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
+ : Buffer(StartBuf), BufferCapacity(Size) {}
+ OutputBuffer(char *StartBuf, size_t *SizePtr)
+ : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
OutputBuffer() = default;
- void reset(char *Buffer_, size_t BufferCapacity_) {
- CurrentPosition = 0;
- Buffer = Buffer_;
- BufferCapacity = BufferCapacity_;
- }
+ // Non-copyable
+ OutputBuffer(const OutputBuffer &) = delete;
+ OutputBuffer &operator=(const OutputBuffer &) = delete;
+
+ operator StringView() const { return StringView(Buffer, CurrentPosition); }
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
+ /// When zero, we're printing template args and '>' needs to be parenthesized.
+ /// Use a counter so we can simply increment inside parentheses.
+ unsigned GtIsGt = 1;
+
+ bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
+
+ void printOpen(char Open = '(') {
+ GtIsGt++;
+ *this += Open;
+ }
+ void printClose(char Close = ')') {
+ GtIsGt--;
+ *this += Close;
+ }
+
OutputBuffer &operator+=(StringView R) {
- size_t Size = R.size();
- if (Size == 0)
- return *this;
- grow(Size);
- std::memmove(Buffer + CurrentPosition, R.begin(), Size);
- CurrentPosition += Size;
+ if (size_t Size = R.size()) {
+ grow(Size);
+ std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
+ CurrentPosition += Size;
+ }
return *this;
}
@@ -97,9 +114,7 @@ public:
return *this;
}
- OutputBuffer &operator<<(StringView R) { return (*this += R); }
-
- OutputBuffer prepend(StringView R) {
+ OutputBuffer &prepend(StringView R) {
size_t Size = R.size();
grow(Size);
@@ -110,19 +125,16 @@ public:
return *this;
}
+ OutputBuffer &operator<<(StringView R) { return (*this += R); }
+
OutputBuffer &operator<<(char C) { return (*this += C); }
OutputBuffer &operator<<(long long N) {
- if (N < 0)
- writeUnsigned(static_cast<unsigned long long>(-N), true);
- else
- writeUnsigned(static_cast<unsigned long long>(N));
- return *this;
+ return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
}
OutputBuffer &operator<<(unsigned long long N) {
- writeUnsigned(N, false);
- return *this;
+ return writeUnsigned(N, false);
}
OutputBuffer &operator<<(long N) {
@@ -155,7 +167,8 @@ public:
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
- return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
+ assert(CurrentPosition);
+ return Buffer[CurrentPosition - 1];
}
bool empty() const { return CurrentPosition == 0; }
@@ -165,52 +178,22 @@ public:
size_t getBufferCapacity() const { return BufferCapacity; }
};
-template <class T> class SwapAndRestore {
- T &Restore;
- T OriginalValue;
- bool ShouldRestore = true;
+template <class T> class ScopedOverride {
+ T &Loc;
+ T Original;
public:
- SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
+ ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
- SwapAndRestore(T &Restore_, T NewVal)
- : Restore(Restore_), OriginalValue(Restore) {
- Restore = std::move(NewVal);
+ ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
+ Loc_ = std::move(NewVal);
}
- ~SwapAndRestore() {
- if (ShouldRestore)
- Restore = std::move(OriginalValue);
- }
-
- void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
-
- void restoreNow(bool Force) {
- if (!Force && !ShouldRestore)
- return;
+ ~ScopedOverride() { Loc = std::move(Original); }
- Restore = std::move(OriginalValue);
- ShouldRestore = false;
- }
-
- SwapAndRestore(const SwapAndRestore &) = delete;
- SwapAndRestore &operator=(const SwapAndRestore &) = delete;
+ ScopedOverride(const ScopedOverride &) = delete;
+ ScopedOverride &operator=(const ScopedOverride &) = delete;
};
-inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
- size_t InitSize) {
- size_t BufferSize;
- if (Buf == nullptr) {
- Buf = static_cast<char *>(std::malloc(InitSize));
- if (Buf == nullptr)
- return false;
- BufferSize = InitSize;
- } else
- BufferSize = *N;
-
- OB.reset(Buf, BufferSize);
- return true;
-}
-
DEMANGLE_NAMESPACE_END
#endif
diff --git a/contrib/libs/cxxsupp/libcxxabi/src/fallback_malloc.cpp b/contrib/libs/cxxsupp/libcxxabi/src/fallback_malloc.cpp
index 0443fd9e62..1ea2a4eb6c 100644
--- a/contrib/libs/cxxsupp/libcxxabi/src/fallback_malloc.cpp
+++ b/contrib/libs/cxxsupp/libcxxabi/src/fallback_malloc.cpp
@@ -19,6 +19,7 @@
#include <__memory/aligned_alloc.h>
#endif
+#include <assert.h>
#include <stdlib.h> // for malloc, calloc, free
#include <string.h> // for memset
#include <new> // for std::__libcpp_aligned_{alloc,free}
@@ -37,10 +38,9 @@ namespace {
// When POSIX threads are not available, make the mutex operations a nop
#ifndef _LIBCXXABI_HAS_NO_THREADS
-_LIBCPP_SAFE_STATIC
-static std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
+static _LIBCPP_CONSTINIT std::__libcpp_mutex_t heap_mutex = _LIBCPP_MUTEX_INITIALIZER;
#else
-static void* heap_mutex = 0;
+static _LIBCPP_CONSTINIT void* heap_mutex = 0;
#endif
class mutexor {
@@ -68,11 +68,28 @@ char heap[HEAP_SIZE] __attribute__((aligned));
typedef unsigned short heap_offset;
typedef unsigned short heap_size;
+// On both 64 and 32 bit targets heap_node should have the following properties
+// Size: 4
+// Alignment: 2
struct heap_node {
heap_offset next_node; // offset into heap
heap_size len; // size in units of "sizeof(heap_node)"
};
+// All pointers returned by fallback_malloc must be at least aligned
+// as RequiredAligned. Note that RequiredAlignment can be greater than
+// alignof(std::max_align_t) on 64 bit systems compiling 32 bit code.
+struct FallbackMaxAlignType {
+} __attribute__((aligned));
+const size_t RequiredAlignment = alignof(FallbackMaxAlignType);
+
+static_assert(alignof(FallbackMaxAlignType) % sizeof(heap_node) == 0,
+ "The required alignment must be evenly divisible by the sizeof(heap_node)");
+
+// The number of heap_node's that can fit in a chunk of memory with the size
+// of the RequiredAlignment. On 64 bit targets NodesPerAlignment should be 4.
+const size_t NodesPerAlignment = alignof(FallbackMaxAlignType) / sizeof(heap_node);
+
static const heap_node* list_end =
(heap_node*)(&heap[HEAP_SIZE]); // one past the end of the heap
static heap_node* freelist = NULL;
@@ -87,10 +104,23 @@ heap_offset offset_from_node(const heap_node* ptr) {
sizeof(heap_node));
}
+// Return a pointer to the first address, 'A', in `heap` that can actually be
+// used to represent a heap_node. 'A' must be aligned so that
+// '(A + sizeof(heap_node)) % RequiredAlignment == 0'. On 64 bit systems this
+// address should be 12 bytes after the first 16 byte boundary.
+heap_node* getFirstAlignedNodeInHeap() {
+ heap_node* node = (heap_node*)heap;
+ const size_t alignNBytesAfterBoundary = RequiredAlignment - sizeof(heap_node);
+ size_t boundaryOffset = reinterpret_cast<size_t>(node) % RequiredAlignment;
+ size_t requiredOffset = alignNBytesAfterBoundary - boundaryOffset;
+ size_t NElemOffset = requiredOffset / sizeof(heap_node);
+ return node + NElemOffset;
+}
+
void init_heap() {
- freelist = (heap_node*)heap;
+ freelist = getFirstAlignedNodeInHeap();
freelist->next_node = offset_from_node(list_end);
- freelist->len = HEAP_SIZE / sizeof(heap_node);
+ freelist->len = static_cast<heap_size>(list_end - freelist);
}
// How big a chunk we allocate
@@ -114,23 +144,44 @@ void* fallback_malloc(size_t len) {
for (p = freelist, prev = 0; p && p != list_end;
prev = p, p = node_from_offset(p->next_node)) {
- if (p->len > nelems) { // chunk is larger, shorten, and return the tail
- heap_node* q;
+ // Check the invariant that all heap_nodes pointers 'p' are aligned
+ // so that 'p + 1' has an alignment of at least RequiredAlignment
+ assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0);
+
+ // Calculate the number of extra padding elements needed in order
+ // to split 'p' and create a properly aligned heap_node from the tail
+ // of 'p'. We calculate aligned_nelems such that 'p->len - aligned_nelems'
+ // will be a multiple of NodesPerAlignment.
+ size_t aligned_nelems = nelems;
+ if (p->len > nelems) {
+ heap_size remaining_len = static_cast<heap_size>(p->len - nelems);
+ aligned_nelems += remaining_len % NodesPerAlignment;
+ }
- p->len = static_cast<heap_size>(p->len - nelems);
+ // chunk is larger and we can create a properly aligned heap_node
+ // from the tail. In this case we shorten 'p' and return the tail.
+ if (p->len > aligned_nelems) {
+ heap_node* q;
+ p->len = static_cast<heap_size>(p->len - aligned_nelems);
q = p + p->len;
q->next_node = 0;
- q->len = static_cast<heap_size>(nelems);
- return (void*)(q + 1);
+ q->len = static_cast<heap_size>(aligned_nelems);
+ void* ptr = q + 1;
+ assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
+ return ptr;
}
- if (p->len == nelems) { // exact size match
+ // The chunk is the exact size or the chunk is larger but not large
+ // enough to split due to alignment constraints.
+ if (p->len >= nelems) {
if (prev == 0)
freelist = node_from_offset(p->next_node);
else
prev->next_node = p->next_node;
p->next_node = 0;
- return (void*)(p + 1);
+ void* ptr = p + 1;
+ assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
+ return ptr;
}
}
return NULL; // couldn't find a spot big enough
diff --git a/contrib/libs/cxxsupp/libcxxabi/ya.make b/contrib/libs/cxxsupp/libcxxabi/ya.make
index 1f739ea96f..2dace23170 100644
--- a/contrib/libs/cxxsupp/libcxxabi/ya.make
+++ b/contrib/libs/cxxsupp/libcxxabi/ya.make
@@ -11,9 +11,9 @@ LICENSE(
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(14.0.6)
+VERSION(16.0.6)
-ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/archive/llvmorg-14.0.6.tar.gz)
+ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/archive/llvmorg-16.0.6.tar.gz)
PEERDIR(
library/cpp/sanitizer/include
diff --git a/util/system/type_name_ut.cpp b/util/system/type_name_ut.cpp
index 86597f4232..c9b2a1e775 100644
--- a/util/system/type_name_ut.cpp
+++ b/util/system/type_name_ut.cpp
@@ -67,10 +67,10 @@ Y_UNIT_TEST_SUITE(TypeName) {
UNIT_ASSERT_VALUES_EQUAL(TypeName<double>(), "double");
#ifdef _MSC_VER
- UNIT_ASSERT_VALUES_EQUAL(TypeName<std::string>(), "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName<std::string>(), "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>>");
UNIT_ASSERT_VALUES_EQUAL(TypeName<std::runtime_error>(), "class std::runtime_error");
#else
- UNIT_ASSERT_VALUES_EQUAL(TypeName<std::string>(), "std::basic_string<char, std::char_traits<char>, std::allocator<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName<std::string>(), "std::basic_string<char, std::char_traits<char>, std::allocator<char>>");
UNIT_ASSERT_VALUES_EQUAL(TypeName<std::runtime_error>(), "std::runtime_error");
#endif
}
@@ -78,10 +78,10 @@ Y_UNIT_TEST_SUITE(TypeName) {
Y_UNIT_TEST(FromArcadiaTypes) {
#ifdef _MSC_VER
UNIT_ASSERT_VALUES_EQUAL(TypeName<yexception>(), "class yexception");
- UNIT_ASSERT_VALUES_EQUAL(TypeName<TString>(), "class TBasicString<char,struct std::char_traits<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName<TString>(), "class TBasicString<char,struct std::char_traits<char>>");
#else
UNIT_ASSERT_VALUES_EQUAL(TypeName<yexception>(), "yexception");
- UNIT_ASSERT_VALUES_EQUAL(TypeName<TString>(), "TBasicString<char, std::char_traits<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName<TString>(), "TBasicString<char, std::char_traits<char>>");
#endif
}
@@ -122,10 +122,10 @@ Y_UNIT_TEST_SUITE(TypeName) {
std::string string;
std::runtime_error err("This is awful");
#ifdef _MSC_VER
- UNIT_ASSERT_VALUES_EQUAL(TypeName(string), "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName(string), "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>>");
UNIT_ASSERT_VALUES_EQUAL(TypeName(err), "class std::runtime_error");
#else
- UNIT_ASSERT_VALUES_EQUAL(TypeName(string), "std::basic_string<char, std::char_traits<char>, std::allocator<char> >");
+ UNIT_ASSERT_VALUES_EQUAL(TypeName(string), "std::basic_string<char, std::char_traits<char>, std::allocator<char>>");
UNIT_ASSERT_VALUES_EQUAL(TypeName(err), "std::runtime_error");
#endif
}
diff --git a/util/system/ut/ya.make b/util/system/ut/ya.make
index f69ca701e5..b6c0512caa 100644
--- a/util/system/ut/ya.make
+++ b/util/system/ut/ya.make
@@ -71,12 +71,17 @@ SRCS(
system/thread_ut.cpp
system/tls_ut.cpp
system/types_ut.cpp
- system/type_name_ut.cpp
system/user_ut.cpp
system/unaligned_mem_ut.cpp
system/yassert_ut.cpp
)
+IF (NOT USE_STL_SYSTEM)
+ SRCS(
+ system/type_name_ut.cpp
+ )
+ENDIF()
+
IF (OS_WINDOWS)
SRCS(
system/fs_win_ut.cpp