mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
libcxxabi: update to LLVM 18
release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db42
This commit is contained in:
Vendored
+11
@@ -36,6 +36,9 @@ class type_info; // forward declaration
|
||||
|
||||
// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
|
||||
namespace __cxxabiv1 {
|
||||
|
||||
struct __cxa_exception;
|
||||
|
||||
extern "C" {
|
||||
|
||||
// 2.4.2 Allocating the Exception Object
|
||||
@@ -43,11 +46,19 @@ extern _LIBCXXABI_FUNC_VIS void *
|
||||
__cxa_allocate_exception(size_t thrown_size) throw();
|
||||
extern _LIBCXXABI_FUNC_VIS void
|
||||
__cxa_free_exception(void *thrown_exception) throw();
|
||||
// This function is an LLVM extension, which mirrors the same extension in libsupc++ and libcxxrt
|
||||
extern _LIBCXXABI_FUNC_VIS __cxa_exception*
|
||||
__cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw();
|
||||
|
||||
// 2.4.3 Throwing the Exception Object
|
||||
extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void
|
||||
__cxa_throw(void *thrown_exception, std::type_info *tinfo,
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
// In Wasm, a destructor returns its argument
|
||||
void *(_LIBCXXABI_DTOR_FUNC *dest)(void *));
|
||||
#else
|
||||
void (_LIBCXXABI_DTOR_FUNC *dest)(void *));
|
||||
#endif
|
||||
|
||||
// 2.5.3 Exception Handlers
|
||||
extern _LIBCXXABI_FUNC_VIS void *
|
||||
|
||||
Vendored
+11
@@ -14,4 +14,15 @@
|
||||
extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void
|
||||
abort_message(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
#ifndef _LIBCXXABI_ASSERT
|
||||
# define _LIBCXXABI_ASSERT(expr, msg) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
char const* __msg = (msg); \
|
||||
::abort_message("%s:%d: %s", __FILE__, __LINE__, __msg); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __ABORT_MESSAGE_H_
|
||||
|
||||
+1
-1
@@ -740,6 +740,6 @@ __catchThrownException(void (*cdfunc)(void), // function which may fail
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
} // __cxxabiv1
|
||||
|
||||
Vendored
+5
-2
@@ -10,14 +10,17 @@
|
||||
// file does not yet support:
|
||||
// - C++ modules TS
|
||||
|
||||
#include "abort_message.h"
|
||||
#define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg)
|
||||
|
||||
#include "demangle/DemangleConfig.h"
|
||||
#include "demangle/ItaniumDemangle.h"
|
||||
#include "__cxxabi_config.h"
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <string_view>
|
||||
@@ -394,7 +397,7 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
|
||||
InternalStatus = demangle_invalid_mangled_name;
|
||||
else {
|
||||
OutputBuffer O(Buf, N);
|
||||
assert(Parser.ForwardTemplateRefs.empty());
|
||||
DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), "");
|
||||
AST->print(O);
|
||||
O += '\0';
|
||||
if (N != nullptr)
|
||||
|
||||
Vendored
+25
-14
@@ -206,6 +206,19 @@ void __cxa_free_exception(void *thrown_object) throw() {
|
||||
__aligned_free_with_fallback((void *)raw_buffer);
|
||||
}
|
||||
|
||||
__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo,
|
||||
void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() {
|
||||
__cxa_exception* exception_header = cxa_exception_from_thrown_object(object);
|
||||
exception_header->referenceCount = 0;
|
||||
exception_header->unexpectedHandler = std::get_unexpected();
|
||||
exception_header->terminateHandler = std::get_terminate();
|
||||
exception_header->exceptionType = tinfo;
|
||||
exception_header->exceptionDestructor = dest;
|
||||
setOurExceptionClass(&exception_header->unwindHeader);
|
||||
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
|
||||
|
||||
return exception_header;
|
||||
}
|
||||
|
||||
// This function shall allocate a __cxa_dependent_exception and
|
||||
// return a pointer to it. (Really to the object, not past its' end).
|
||||
@@ -254,23 +267,21 @@ will call terminate, assuming that there was no handler for the
|
||||
exception.
|
||||
*/
|
||||
void
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
// In Wasm, a destructor returns its 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 (_LIBCXXABI_DTOR_FUNC *dest)(void *)) {
|
||||
__cxa_eh_globals *globals = __cxa_get_globals();
|
||||
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
|
||||
#endif
|
||||
__cxa_eh_globals* globals = __cxa_get_globals();
|
||||
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
|
||||
|
||||
exception_header->unexpectedHandler = std::get_unexpected();
|
||||
exception_header->terminateHandler = std::get_terminate();
|
||||
exception_header->exceptionType = tinfo;
|
||||
exception_header->exceptionDestructor = dest;
|
||||
setOurExceptionClass(&exception_header->unwindHeader);
|
||||
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
|
||||
globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
|
||||
|
||||
exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
|
||||
__cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest);
|
||||
exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
|
||||
|
||||
#if __has_feature(address_sanitizer)
|
||||
// Inform the ASan runtime that now might be a good time to clean stuff up.
|
||||
__asan_handle_no_return();
|
||||
// Inform the ASan runtime that now might be a good time to clean stuff up.
|
||||
__asan_handle_no_return();
|
||||
#endif
|
||||
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
@@ -771,6 +782,6 @@ __cxa_uncaught_exceptions() throw()
|
||||
return globals->uncaughtExceptions;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
} // abi
|
||||
|
||||
Vendored
+5
@@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
|
||||
|
||||
// Manage the exception object itself.
|
||||
std::type_info *exceptionType;
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
// In Wasm, a destructor returns its argument
|
||||
void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||
#else
|
||||
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
|
||||
#endif
|
||||
std::unexpected_handler unexpectedHandler;
|
||||
std::terminate_handler terminateHandler;
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -48,6 +48,6 @@ _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) {
|
||||
SelectedImplementation imp(raw_guard_object);
|
||||
imp.cxa_guard_abort();
|
||||
}
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
} // __cxxabiv1
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ __cxa_uncaught_exception() throw() { return false; }
|
||||
unsigned int
|
||||
__cxa_uncaught_exceptions() throw() { return 0; }
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
// provide dummy implementations for the 'no exceptions' case.
|
||||
uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; }
|
||||
|
||||
+29
-23
@@ -70,7 +70,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
|
||||
+------------------+--+-----+-----+------------------------+--------------------------+
|
||||
| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
|
||||
+---------------------+-----------+---------------------------------------------------+
|
||||
#ifndef __USING_SJLJ_EXCEPTIONS__
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
|
||||
+---------------------+-----------+------------------------------------------------+
|
||||
| Beginning of Call Site Table The current ip lies within the |
|
||||
| ... (start, length) range of one of these |
|
||||
@@ -84,7 +84,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
|
||||
| +-------------+---------------------------------+------------------------------+ |
|
||||
| ... |
|
||||
+----------------------------------------------------------------------------------+
|
||||
#else // __USING_SJLJ_EXCEPTIONS__
|
||||
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
+---------------------+-----------+------------------------------------------------+
|
||||
| Beginning of Call Site Table The current ip is a 1-based index into |
|
||||
| ... this table. Or it is -1 meaning no |
|
||||
@@ -97,7 +97,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
|
||||
| +-------------+---------------------------------+------------------------------+ |
|
||||
| ... |
|
||||
+----------------------------------------------------------------------------------+
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
+---------------------------------------------------------------------+
|
||||
| Beginning of Action Table ttypeIndex == 0 : cleanup |
|
||||
| ... ttypeIndex > 0 : catch |
|
||||
@@ -547,7 +547,7 @@ void
|
||||
set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
|
||||
const scan_results& results)
|
||||
{
|
||||
#if defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
|
||||
#define __builtin_eh_return_data_regno(regno) regno
|
||||
#elif defined(__ibmxl__)
|
||||
// IBM xlclang++ compiler does not support __builtin_eh_return_data_regno.
|
||||
@@ -642,7 +642,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
// Get beginning current frame's code (as defined by the
|
||||
// emitted dwarf code)
|
||||
uintptr_t funcStart = _Unwind_GetRegionStart(context);
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
|
||||
if (ip == uintptr_t(-1))
|
||||
{
|
||||
// no action
|
||||
@@ -652,18 +652,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
else if (ip == 0)
|
||||
call_terminate(native_exception, unwind_exception);
|
||||
// ip is 1-based index into call site table
|
||||
#else // !__USING_SJLJ_EXCEPTIONS__
|
||||
#else // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
|
||||
uintptr_t ipOffset = ip - funcStart;
|
||||
#endif // !defined(_USING_SLJL_EXCEPTIONS__)
|
||||
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
|
||||
const uint8_t* classInfo = NULL;
|
||||
// Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
|
||||
// dwarf emission
|
||||
// Parse LSDA header.
|
||||
uint8_t lpStartEncoding = *lsda++;
|
||||
const uint8_t* lpStart =
|
||||
(const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
|
||||
if (lpStart == 0)
|
||||
lpStart = (const uint8_t*)funcStart;
|
||||
const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit
|
||||
? (const uint8_t*)funcStart
|
||||
: (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base);
|
||||
uint8_t ttypeEncoding = *lsda++;
|
||||
if (ttypeEncoding != DW_EH_PE_omit)
|
||||
{
|
||||
@@ -676,8 +675,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
// Walk call-site table looking for range that
|
||||
// includes current PC.
|
||||
uint8_t callSiteEncoding = *lsda++;
|
||||
#ifdef __USING_SJLJ_EXCEPTIONS__
|
||||
(void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used
|
||||
#if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__)
|
||||
(void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used
|
||||
#endif
|
||||
uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda));
|
||||
const uint8_t* callSiteTableStart = lsda;
|
||||
@@ -687,7 +686,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
while (callSitePtr < callSiteTableEnd)
|
||||
{
|
||||
// There is one entry per call site.
|
||||
#ifndef __USING_SJLJ_EXCEPTIONS__
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
|
||||
// The call sites are non-overlapping in [start, start+length)
|
||||
// The call sites are ordered in increasing value of start
|
||||
uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
|
||||
@@ -695,15 +694,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
|
||||
uintptr_t actionEntry = readULEB128(&callSitePtr);
|
||||
if ((start <= ipOffset) && (ipOffset < (start + length)))
|
||||
#else // __USING_SJLJ_EXCEPTIONS__
|
||||
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
// ip is 1-based index into this table
|
||||
uintptr_t landingPad = readULEB128(&callSitePtr);
|
||||
uintptr_t actionEntry = readULEB128(&callSitePtr);
|
||||
if (--ip == 0)
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
{
|
||||
// Found the call site containing ip.
|
||||
#ifndef __USING_SJLJ_EXCEPTIONS__
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
|
||||
if (landingPad == 0)
|
||||
{
|
||||
// No handler here
|
||||
@@ -711,9 +710,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
return;
|
||||
}
|
||||
landingPad = (uintptr_t)lpStart + landingPad;
|
||||
#else // __USING_SJLJ_EXCEPTIONS__
|
||||
#else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
++landingPad;
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__
|
||||
#endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__
|
||||
results.landingPad = landingPad;
|
||||
if (actionEntry == 0)
|
||||
{
|
||||
@@ -841,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
action += actionOffset;
|
||||
} // there is no break out of this loop, only return
|
||||
}
|
||||
#ifndef __USING_SJLJ_EXCEPTIONS__
|
||||
#if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__)
|
||||
else if (ipOffset < start)
|
||||
{
|
||||
// There is no call site for this ip
|
||||
@@ -849,7 +848,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
|
||||
// Possible stack corruption.
|
||||
call_terminate(native_exception, unwind_exception);
|
||||
}
|
||||
#endif // !__USING_SJLJ_EXCEPTIONS__
|
||||
#endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__
|
||||
} // there might be some tricky cases which break out of this loop
|
||||
|
||||
// It is possible that no eh table entry specify how to handle
|
||||
@@ -906,7 +905,9 @@ _UA_CLEANUP_PHASE
|
||||
*/
|
||||
|
||||
#if !defined(_LIBCXXABI_ARM_EHABI)
|
||||
#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
_Unwind_Reason_Code __gxx_personality_wasm0
|
||||
#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
|
||||
static _Unwind_Reason_Code __gxx_personality_imp
|
||||
#else
|
||||
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
|
||||
@@ -973,6 +974,11 @@ __gxx_personality_v0
|
||||
exc->languageSpecificData = results.languageSpecificData;
|
||||
exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
|
||||
exc->adjustedPtr = results.adjustedPtr;
|
||||
#ifdef __USING_WASM_EXCEPTIONS__
|
||||
// Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
|
||||
// results here.
|
||||
set_registers(unwind_exception, context, results);
|
||||
#endif
|
||||
}
|
||||
return _URC_HANDLER_FOUND;
|
||||
}
|
||||
@@ -1304,7 +1310,7 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1(
|
||||
__attribute__((__alias__("__gxx_personality_v0")));
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
} // __cxxabiv1
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -416,6 +416,6 @@ __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size,
|
||||
}
|
||||
|
||||
|
||||
} // extern "C"
|
||||
} // extern "C"
|
||||
|
||||
} // abi
|
||||
|
||||
+6
-1
@@ -19,7 +19,7 @@
|
||||
#include "../abort_message.h"
|
||||
#endif
|
||||
|
||||
#include <ciso646>
|
||||
#include <version>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// snprintf is implemented in VS 2015
|
||||
@@ -99,6 +99,11 @@
|
||||
#define DEMANGLE_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#ifndef DEMANGLE_ASSERT
|
||||
#include <cassert>
|
||||
#define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg))
|
||||
#endif
|
||||
|
||||
#define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle {
|
||||
#define DEMANGLE_NAMESPACE_END } }
|
||||
|
||||
|
||||
+538
-103
@@ -21,7 +21,6 @@
|
||||
#include "Utility.h"
|
||||
#include <__cxxabi_config.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -61,13 +60,13 @@ template <class T, size_t N> class PODSmallVector {
|
||||
if (isInline()) {
|
||||
auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T)));
|
||||
if (Tmp == nullptr)
|
||||
std::terminate();
|
||||
std::abort();
|
||||
std::copy(First, Last, Tmp);
|
||||
First = Tmp;
|
||||
} else {
|
||||
First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T)));
|
||||
if (First == nullptr)
|
||||
std::terminate();
|
||||
std::abort();
|
||||
}
|
||||
Last = First + S;
|
||||
Cap = First + NewCap;
|
||||
@@ -129,12 +128,12 @@ public:
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
void pop_back() {
|
||||
assert(Last != First && "Popping empty vector!");
|
||||
DEMANGLE_ASSERT(Last != First, "Popping empty vector!");
|
||||
--Last;
|
||||
}
|
||||
|
||||
void dropBack(size_t Index) {
|
||||
assert(Index <= size() && "dropBack() can't expand!");
|
||||
void shrinkToSize(size_t Index) {
|
||||
DEMANGLE_ASSERT(Index <= size(), "shrinkToSize() can't expand!");
|
||||
Last = First + Index;
|
||||
}
|
||||
|
||||
@@ -144,11 +143,11 @@ public:
|
||||
bool empty() const { return First == Last; }
|
||||
size_t size() const { return static_cast<size_t>(Last - First); }
|
||||
T &back() {
|
||||
assert(Last != First && "Calling back() on empty vector!");
|
||||
DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!");
|
||||
return *(Last - 1);
|
||||
}
|
||||
T &operator[](size_t Index) {
|
||||
assert(Index < size() && "Invalid access!");
|
||||
DEMANGLE_ASSERT(Index < size(), "Invalid access!");
|
||||
return *(begin() + Index);
|
||||
}
|
||||
void clear() { Last = First; }
|
||||
@@ -534,6 +533,23 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TransformedType : public Node {
|
||||
std::string_view Transform;
|
||||
Node *BaseType;
|
||||
public:
|
||||
TransformedType(std::string_view Transform_, Node *BaseType_)
|
||||
: Node(KTransformedType), Transform(Transform_), BaseType(BaseType_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Transform, BaseType); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += Transform;
|
||||
OB += '(';
|
||||
BaseType->print(OB);
|
||||
OB += ')';
|
||||
}
|
||||
};
|
||||
|
||||
struct AbiTagAttr : Node {
|
||||
Node *Base;
|
||||
std::string_view Tag;
|
||||
@@ -873,26 +889,53 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the explicitly named object parameter.
|
||||
/// E.g.,
|
||||
/// \code{.cpp}
|
||||
/// struct Foo {
|
||||
/// void bar(this Foo && self);
|
||||
/// };
|
||||
/// \endcode
|
||||
class ExplicitObjectParameter final : public Node {
|
||||
Node *Base;
|
||||
|
||||
public:
|
||||
ExplicitObjectParameter(Node *Base_)
|
||||
: Node(KExplicitObjectParameter), Base(Base_) {
|
||||
DEMANGLE_ASSERT(
|
||||
Base != nullptr,
|
||||
"Creating an ExplicitObjectParameter without a valid Base Node.");
|
||||
}
|
||||
|
||||
template <typename Fn> void match(Fn F) const { F(Base); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "this ";
|
||||
Base->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionEncoding final : public Node {
|
||||
const Node *Ret;
|
||||
const Node *Name;
|
||||
NodeArray Params;
|
||||
const Node *Attrs;
|
||||
const Node *Requires;
|
||||
Qualifiers CVQuals;
|
||||
FunctionRefQual RefQual;
|
||||
|
||||
public:
|
||||
FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
|
||||
const Node *Attrs_, Qualifiers CVQuals_,
|
||||
FunctionRefQual RefQual_)
|
||||
const Node *Attrs_, const Node *Requires_,
|
||||
Qualifiers CVQuals_, FunctionRefQual RefQual_)
|
||||
: Node(KFunctionEncoding,
|
||||
/*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
|
||||
/*FunctionCache=*/Cache::Yes),
|
||||
Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
|
||||
CVQuals(CVQuals_), RefQual(RefQual_) {}
|
||||
Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const {
|
||||
F(Ret, Name, Params, Attrs, CVQuals, RefQual);
|
||||
F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual);
|
||||
}
|
||||
|
||||
Qualifiers getCVQuals() const { return CVQuals; }
|
||||
@@ -935,6 +978,11 @@ public:
|
||||
|
||||
if (Attrs != nullptr)
|
||||
Attrs->print(OB);
|
||||
|
||||
if (Requires != nullptr) {
|
||||
OB += " requires ";
|
||||
Requires->print(OB);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1006,6 +1054,24 @@ struct NestedName : Node {
|
||||
}
|
||||
};
|
||||
|
||||
struct MemberLikeFriendName : Node {
|
||||
Node *Qual;
|
||||
Node *Name;
|
||||
|
||||
MemberLikeFriendName(Node *Qual_, Node *Name_)
|
||||
: Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Qual, Name); }
|
||||
|
||||
std::string_view getBaseName() const override { return Name->getBaseName(); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Qual->print(OB);
|
||||
OB += "::friend ";
|
||||
Name->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
struct ModuleName : Node {
|
||||
ModuleName *Parent;
|
||||
Node *Name;
|
||||
@@ -1171,6 +1237,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class TemplateParamQualifiedArg final : public Node {
|
||||
Node *Param;
|
||||
Node *Arg;
|
||||
|
||||
public:
|
||||
TemplateParamQualifiedArg(Node *Param_, Node *Arg_)
|
||||
: Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {}
|
||||
|
||||
template <typename Fn> void match(Fn F) const { F(Param, Arg); }
|
||||
|
||||
Node *getArg() { return Arg; }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
// Don't print Param to keep the output consistent.
|
||||
Arg->print(OB);
|
||||
}
|
||||
};
|
||||
|
||||
/// A template type parameter declaration, 'typename T'.
|
||||
class TypeTemplateParamDecl final : public Node {
|
||||
Node *Name;
|
||||
@@ -1186,6 +1270,26 @@ public:
|
||||
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
|
||||
};
|
||||
|
||||
/// A constrained template type parameter declaration, 'C<U> T'.
|
||||
class ConstrainedTypeTemplateParamDecl final : public Node {
|
||||
Node *Constraint;
|
||||
Node *Name;
|
||||
|
||||
public:
|
||||
ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_)
|
||||
: Node(KConstrainedTypeTemplateParamDecl, Cache::Yes),
|
||||
Constraint(Constraint_), Name(Name_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Constraint, Name); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
Constraint->print(OB);
|
||||
OB += " ";
|
||||
}
|
||||
|
||||
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
|
||||
};
|
||||
|
||||
/// A non-type template parameter declaration, 'int N'.
|
||||
class NonTypeTemplateParamDecl final : public Node {
|
||||
Node *Name;
|
||||
@@ -1214,13 +1318,14 @@ public:
|
||||
class TemplateTemplateParamDecl final : public Node {
|
||||
Node *Name;
|
||||
NodeArray Params;
|
||||
Node *Requires;
|
||||
|
||||
public:
|
||||
TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
|
||||
TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_)
|
||||
: Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
|
||||
Params(Params_) {}
|
||||
Params(Params_), Requires(Requires_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Name, Params); }
|
||||
template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
|
||||
@@ -1229,7 +1334,13 @@ public:
|
||||
OB += "> typename ";
|
||||
}
|
||||
|
||||
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
|
||||
void printRight(OutputBuffer &OB) const override {
|
||||
Name->print(OB);
|
||||
if (Requires != nullptr) {
|
||||
OB += " requires ";
|
||||
Requires->print(OB);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// A template parameter pack declaration, 'typename ...T'.
|
||||
@@ -1326,7 +1437,7 @@ public:
|
||||
|
||||
/// A variadic template argument. This node represents an occurrence of
|
||||
/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
|
||||
/// one of it's Elements is. The parser inserts a ParameterPack into the
|
||||
/// one of its Elements is. The parser inserts a ParameterPack into the
|
||||
/// TemplateParams table if the <template-args> this pack belongs to apply to an
|
||||
/// <encoding>.
|
||||
class TemplateArgumentPack final : public Node {
|
||||
@@ -1392,11 +1503,13 @@ public:
|
||||
|
||||
class TemplateArgs final : public Node {
|
||||
NodeArray Params;
|
||||
Node *Requires;
|
||||
|
||||
public:
|
||||
TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
|
||||
TemplateArgs(NodeArray Params_, Node *Requires_)
|
||||
: Node(KTemplateArgs), Params(Params_), Requires(Requires_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Params); }
|
||||
template<typename Fn> void match(Fn F) const { F(Params, Requires); }
|
||||
|
||||
NodeArray getParams() { return Params; }
|
||||
|
||||
@@ -1405,6 +1518,7 @@ public:
|
||||
OB += "<";
|
||||
Params.printWithComma(OB);
|
||||
OB += ">";
|
||||
// Don't print the requires clause to keep the output simple.
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1589,7 +1703,7 @@ public:
|
||||
std::string_view SV = ExpandedSpecialSubstitution::getBaseName();
|
||||
if (isInstantiation()) {
|
||||
// The instantiations are typedefs that drop the "basic_" prefix.
|
||||
assert(starts_with(SV, "basic_"));
|
||||
DEMANGLE_ASSERT(starts_with(SV, "basic_"), "");
|
||||
SV.remove_prefix(sizeof("basic_") - 1);
|
||||
}
|
||||
return SV;
|
||||
@@ -1655,17 +1769,21 @@ public:
|
||||
|
||||
class ClosureTypeName : public Node {
|
||||
NodeArray TemplateParams;
|
||||
const Node *Requires1;
|
||||
NodeArray Params;
|
||||
const Node *Requires2;
|
||||
std::string_view Count;
|
||||
|
||||
public:
|
||||
ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
|
||||
ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_,
|
||||
NodeArray Params_, const Node *Requires2_,
|
||||
std::string_view Count_)
|
||||
: Node(KClosureTypeName), TemplateParams(TemplateParams_),
|
||||
Params(Params_), Count(Count_) {}
|
||||
Requires1(Requires1_), Params(Params_), Requires2(Requires2_),
|
||||
Count(Count_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const {
|
||||
F(TemplateParams, Params, Count);
|
||||
F(TemplateParams, Requires1, Params, Requires2, Count);
|
||||
}
|
||||
|
||||
void printDeclarator(OutputBuffer &OB) const {
|
||||
@@ -1675,12 +1793,22 @@ public:
|
||||
TemplateParams.printWithComma(OB);
|
||||
OB += ">";
|
||||
}
|
||||
if (Requires1 != nullptr) {
|
||||
OB += " requires ";
|
||||
Requires1->print(OB);
|
||||
OB += " ";
|
||||
}
|
||||
OB.printOpen();
|
||||
Params.printWithComma(OB);
|
||||
OB.printClose();
|
||||
if (Requires2 != nullptr) {
|
||||
OB += " requires ";
|
||||
Requires2->print(OB);
|
||||
}
|
||||
}
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
// FIXME: This demangling is not particularly readable.
|
||||
OB += "\'lambda";
|
||||
OB += Count;
|
||||
OB += "\'";
|
||||
@@ -2309,6 +2437,95 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class RequiresExpr : public Node {
|
||||
NodeArray Parameters;
|
||||
NodeArray Requirements;
|
||||
public:
|
||||
RequiresExpr(NodeArray Parameters_, NodeArray Requirements_)
|
||||
: Node(KRequiresExpr), Parameters(Parameters_),
|
||||
Requirements(Requirements_) {}
|
||||
|
||||
template<typename Fn> void match(Fn F) const { F(Parameters, Requirements); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += "requires";
|
||||
if (!Parameters.empty()) {
|
||||
OB += ' ';
|
||||
OB.printOpen();
|
||||
Parameters.printWithComma(OB);
|
||||
OB.printClose();
|
||||
}
|
||||
OB += ' ';
|
||||
OB.printOpen('{');
|
||||
for (const Node *Req : Requirements) {
|
||||
Req->print(OB);
|
||||
}
|
||||
OB += ' ';
|
||||
OB.printClose('}');
|
||||
}
|
||||
};
|
||||
|
||||
class ExprRequirement : public Node {
|
||||
const Node *Expr;
|
||||
bool IsNoexcept;
|
||||
const Node *TypeConstraint;
|
||||
public:
|
||||
ExprRequirement(const Node *Expr_, bool IsNoexcept_,
|
||||
const Node *TypeConstraint_)
|
||||
: Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_),
|
||||
TypeConstraint(TypeConstraint_) {}
|
||||
|
||||
template <typename Fn> void match(Fn F) const {
|
||||
F(Expr, IsNoexcept, TypeConstraint);
|
||||
}
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += " ";
|
||||
if (IsNoexcept || TypeConstraint)
|
||||
OB.printOpen('{');
|
||||
Expr->print(OB);
|
||||
if (IsNoexcept || TypeConstraint)
|
||||
OB.printClose('}');
|
||||
if (IsNoexcept)
|
||||
OB += " noexcept";
|
||||
if (TypeConstraint) {
|
||||
OB += " -> ";
|
||||
TypeConstraint->print(OB);
|
||||
}
|
||||
OB += ';';
|
||||
}
|
||||
};
|
||||
|
||||
class TypeRequirement : public Node {
|
||||
const Node *Type;
|
||||
public:
|
||||
TypeRequirement(const Node *Type_)
|
||||
: Node(KTypeRequirement), Type(Type_) {}
|
||||
|
||||
template <typename Fn> void match(Fn F) const { F(Type); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += " typename ";
|
||||
Type->print(OB);
|
||||
OB += ';';
|
||||
}
|
||||
};
|
||||
|
||||
class NestedRequirement : public Node {
|
||||
const Node *Constraint;
|
||||
public:
|
||||
NestedRequirement(const Node *Constraint_)
|
||||
: Node(KNestedRequirement), Constraint(Constraint_) {}
|
||||
|
||||
template <typename Fn> void match(Fn F) const { F(Constraint); }
|
||||
|
||||
void printLeft(OutputBuffer &OB) const override {
|
||||
OB += " requires ";
|
||||
Constraint->print(OB);
|
||||
OB += ';';
|
||||
}
|
||||
};
|
||||
|
||||
template <class Float> struct FloatData;
|
||||
|
||||
namespace float_literal_impl {
|
||||
@@ -2377,7 +2594,7 @@ void Node::visit(Fn F) const {
|
||||
return F(static_cast<const X *>(this));
|
||||
#include "ItaniumNodes.def"
|
||||
}
|
||||
assert(0 && "unknown mangling node kind");
|
||||
DEMANGLE_ASSERT(0, "unknown mangling node kind");
|
||||
}
|
||||
|
||||
/// Determine the kind of a node from its type.
|
||||
@@ -2403,6 +2620,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
// table.
|
||||
PODSmallVector<Node *, 32> Subs;
|
||||
|
||||
// A list of template argument values corresponding to a template parameter
|
||||
// list.
|
||||
using TemplateParamList = PODSmallVector<Node *, 8>;
|
||||
|
||||
class ScopedTemplateParamList {
|
||||
@@ -2417,9 +2636,11 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
Parser->TemplateParams.push_back(&Params);
|
||||
}
|
||||
~ScopedTemplateParamList() {
|
||||
assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
|
||||
Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
|
||||
DEMANGLE_ASSERT(Parser->TemplateParams.size() >= OldNumTemplateParamLists,
|
||||
"");
|
||||
Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists);
|
||||
}
|
||||
TemplateParamList *params() { return &Params; }
|
||||
};
|
||||
|
||||
// Template parameter table. Like the above, but referenced like "T42_".
|
||||
@@ -2434,12 +2655,31 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
// parameter list, the corresponding parameter list pointer will be null.
|
||||
PODSmallVector<TemplateParamList *, 4> TemplateParams;
|
||||
|
||||
class SaveTemplateParams {
|
||||
AbstractManglingParser *Parser;
|
||||
decltype(TemplateParams) OldParams;
|
||||
decltype(OuterTemplateParams) OldOuterParams;
|
||||
|
||||
public:
|
||||
SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
|
||||
OldParams = std::move(Parser->TemplateParams);
|
||||
OldOuterParams = std::move(Parser->OuterTemplateParams);
|
||||
Parser->TemplateParams.clear();
|
||||
Parser->OuterTemplateParams.clear();
|
||||
}
|
||||
~SaveTemplateParams() {
|
||||
Parser->TemplateParams = std::move(OldParams);
|
||||
Parser->OuterTemplateParams = std::move(OldOuterParams);
|
||||
}
|
||||
};
|
||||
|
||||
// Set of unresolved forward <template-param> references. These can occur in a
|
||||
// conversion operator's type, and are resolved in the enclosing <encoding>.
|
||||
PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
|
||||
|
||||
bool TryToParseTemplateArgs = true;
|
||||
bool PermitForwardTemplateReferences = false;
|
||||
bool InConstraintExpr = false;
|
||||
size_t ParsingLambdaParamsAtLevel = (size_t)-1;
|
||||
|
||||
unsigned NumSyntheticTemplateParameters[3] = {};
|
||||
@@ -2478,10 +2718,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
}
|
||||
|
||||
NodeArray popTrailingNodeArray(size_t FromPosition) {
|
||||
assert(FromPosition <= Names.size());
|
||||
DEMANGLE_ASSERT(FromPosition <= Names.size(), "");
|
||||
NodeArray res =
|
||||
makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
|
||||
Names.dropBack(FromPosition);
|
||||
Names.shrinkToSize(FromPosition);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2519,11 +2759,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
bool parseSeqId(size_t *Out);
|
||||
Node *parseSubstitution();
|
||||
Node *parseTemplateParam();
|
||||
Node *parseTemplateParamDecl();
|
||||
Node *parseTemplateParamDecl(TemplateParamList *Params);
|
||||
Node *parseTemplateArgs(bool TagTemplates = false);
|
||||
Node *parseTemplateArg();
|
||||
|
||||
/// Parse the <expr> production.
|
||||
bool isTemplateParamDecl() {
|
||||
return look() == 'T' &&
|
||||
std::string_view("yptnk").find(look(1)) != std::string_view::npos;
|
||||
}
|
||||
|
||||
/// Parse the <expression> production.
|
||||
Node *parseExpr();
|
||||
Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec);
|
||||
Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec);
|
||||
@@ -2536,6 +2781,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
Node *parseFoldExpr();
|
||||
Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
|
||||
Node *parseSubobjectExpr();
|
||||
Node *parseConstraintExpr();
|
||||
Node *parseRequiresExpr();
|
||||
|
||||
/// Parse the <type> production.
|
||||
Node *parseType();
|
||||
@@ -2547,7 +2794,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
Node *parseClassEnumType();
|
||||
Node *parseQualifiedType();
|
||||
|
||||
Node *parseEncoding();
|
||||
Node *parseEncoding(bool ParseParams = true);
|
||||
bool parseCallOffset();
|
||||
Node *parseSpecialName();
|
||||
|
||||
@@ -2559,6 +2806,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
Qualifiers CVQualifiers = QualNone;
|
||||
FunctionRefQual ReferenceQualifier = FrefQualNone;
|
||||
size_t ForwardTemplateRefsBegin;
|
||||
bool HasExplicitObjectParameter = false;
|
||||
|
||||
NameState(AbstractManglingParser *Enclosing)
|
||||
: ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
|
||||
@@ -2574,7 +2822,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
return true;
|
||||
ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
|
||||
}
|
||||
ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
|
||||
ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2638,8 +2886,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
std::string_view getSymbol() const {
|
||||
std::string_view Res = Name;
|
||||
if (Kind < Unnameable) {
|
||||
assert(starts_with(Res, "operator") &&
|
||||
"operator name does not start with 'operator'");
|
||||
DEMANGLE_ASSERT(starts_with(Res, "operator"),
|
||||
"operator name does not start with 'operator'");
|
||||
Res.remove_prefix(sizeof("operator") - 1);
|
||||
if (starts_with(Res, ' '))
|
||||
Res.remove_prefix(1);
|
||||
@@ -2663,7 +2911,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
|
||||
Node *parseDestructorName();
|
||||
|
||||
/// Top-level entry point into the parser.
|
||||
Node *parse();
|
||||
Node *parse(bool ParseParams = true);
|
||||
};
|
||||
|
||||
const char* parse_discriminator(const char* first, const char* last);
|
||||
@@ -2727,6 +2975,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
|
||||
return make<LocalName>(Encoding, StringLitName);
|
||||
}
|
||||
|
||||
// The template parameters of the inner name are unrelated to those of the
|
||||
// enclosing context.
|
||||
SaveTemplateParams SaveTemplateParamsScope(this);
|
||||
|
||||
if (consumeIf('d')) {
|
||||
parseNumber(true);
|
||||
if (!consumeIf('_'))
|
||||
@@ -2782,9 +3034,9 @@ AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
|
||||
return Res;
|
||||
}
|
||||
|
||||
// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
|
||||
// <unqualified-name> ::= [<module-name>] F? L? <operator-name> [<abi-tags>]
|
||||
// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
|
||||
// ::= [<module-name>] L? <source-name> [<abi-tags>]
|
||||
// ::= [<module-name>] F? L? <source-name> [<abi-tags>]
|
||||
// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
|
||||
// # structured binding declaration
|
||||
// ::= [<module-name>] L? DC <source-name>+ E
|
||||
@@ -2794,6 +3046,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
|
||||
if (getDerived().parseModuleNameOpt(Module))
|
||||
return nullptr;
|
||||
|
||||
bool IsMemberLikeFriend = Scope && consumeIf('F');
|
||||
|
||||
consumeIf('L');
|
||||
|
||||
Node *Result;
|
||||
@@ -2824,7 +3078,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
|
||||
Result = make<ModuleEntity>(Module, Result);
|
||||
if (Result != nullptr)
|
||||
Result = getDerived().parseAbiTags(Result);
|
||||
if (Result != nullptr && Scope != nullptr)
|
||||
if (Result != nullptr && IsMemberLikeFriend)
|
||||
Result = make<MemberLikeFriendName>(Scope, Result);
|
||||
else if (Result != nullptr && Scope != nullptr)
|
||||
Result = make<NestedName>(Scope, Result);
|
||||
|
||||
return Result;
|
||||
@@ -2856,7 +3112,8 @@ bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
|
||||
//
|
||||
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
|
||||
//
|
||||
// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
|
||||
// <lambda-sig> ::= <template-param-decl>* [Q <requires-clause expression>]
|
||||
// <parameter type>+ # or "v" if the lambda has no parameters
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *
|
||||
AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
|
||||
@@ -2877,10 +3134,10 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
|
||||
ScopedTemplateParamList LambdaTemplateParams(this);
|
||||
|
||||
size_t ParamsBegin = Names.size();
|
||||
while (look() == 'T' &&
|
||||
std::string_view("yptn").find(look(1)) != std::string_view::npos) {
|
||||
Node *T = parseTemplateParamDecl();
|
||||
if (!T)
|
||||
while (getDerived().isTemplateParamDecl()) {
|
||||
Node *T =
|
||||
getDerived().parseTemplateParamDecl(LambdaTemplateParams.params());
|
||||
if (T == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(T);
|
||||
}
|
||||
@@ -2911,20 +3168,38 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
|
||||
if (TempParams.empty())
|
||||
TemplateParams.pop_back();
|
||||
|
||||
if (!consumeIf("vE")) {
|
||||
Node *Requires1 = nullptr;
|
||||
if (consumeIf('Q')) {
|
||||
Requires1 = getDerived().parseConstraintExpr();
|
||||
if (Requires1 == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!consumeIf("v")) {
|
||||
do {
|
||||
Node *P = getDerived().parseType();
|
||||
if (P == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(P);
|
||||
} while (!consumeIf('E'));
|
||||
} while (look() != 'E' && look() != 'Q');
|
||||
}
|
||||
NodeArray Params = popTrailingNodeArray(ParamsBegin);
|
||||
|
||||
Node *Requires2 = nullptr;
|
||||
if (consumeIf('Q')) {
|
||||
Requires2 = getDerived().parseConstraintExpr();
|
||||
if (Requires2 == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!consumeIf('E'))
|
||||
return nullptr;
|
||||
|
||||
std::string_view Count = parseNumber();
|
||||
if (!consumeIf('_'))
|
||||
return nullptr;
|
||||
return make<ClosureTypeName>(TempParams, Params, Count);
|
||||
return make<ClosureTypeName>(TempParams, Requires1, Params, Requires2,
|
||||
Count);
|
||||
}
|
||||
if (consumeIf("Ub")) {
|
||||
(void)parseNumber();
|
||||
@@ -3190,15 +3465,25 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) {
|
||||
if (!consumeIf('N'))
|
||||
return nullptr;
|
||||
|
||||
Qualifiers CVTmp = parseCVQualifiers();
|
||||
if (State) State->CVQualifiers = CVTmp;
|
||||
// 'H' specifies that the encoding that follows
|
||||
// has an explicit object parameter.
|
||||
if (!consumeIf('H')) {
|
||||
Qualifiers CVTmp = parseCVQualifiers();
|
||||
if (State)
|
||||
State->CVQualifiers = CVTmp;
|
||||
|
||||
if (consumeIf('O')) {
|
||||
if (State) State->ReferenceQualifier = FrefQualRValue;
|
||||
} else if (consumeIf('R')) {
|
||||
if (State) State->ReferenceQualifier = FrefQualLValue;
|
||||
} else {
|
||||
if (State) State->ReferenceQualifier = FrefQualNone;
|
||||
if (consumeIf('O')) {
|
||||
if (State)
|
||||
State->ReferenceQualifier = FrefQualRValue;
|
||||
} else if (consumeIf('R')) {
|
||||
if (State)
|
||||
State->ReferenceQualifier = FrefQualLValue;
|
||||
} else {
|
||||
if (State)
|
||||
State->ReferenceQualifier = FrefQualNone;
|
||||
}
|
||||
} else if (State) {
|
||||
State->HasExplicitObjectParameter = true;
|
||||
}
|
||||
|
||||
Node *SoFar = nullptr;
|
||||
@@ -3446,7 +3731,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) {
|
||||
}
|
||||
}
|
||||
|
||||
assert(SoFar != nullptr);
|
||||
DEMANGLE_ASSERT(SoFar != nullptr, "");
|
||||
|
||||
Node *Base = getDerived().parseBaseUnresolvedName();
|
||||
if (Base == nullptr)
|
||||
@@ -3894,7 +4179,15 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
|
||||
// Typically, <builtin-type>s are not considered substitution candidates,
|
||||
// but the exception to that exception is vendor extended types (Itanium C++
|
||||
// ABI 5.9.1).
|
||||
Result = make<NameType>(Res);
|
||||
if (consumeIf('I')) {
|
||||
Node *BaseType = parseType();
|
||||
if (BaseType == nullptr)
|
||||
return nullptr;
|
||||
if (!consumeIf('E'))
|
||||
return nullptr;
|
||||
Result = make<TransformedType>(Res, BaseType);
|
||||
} else
|
||||
Result = make<NameType>(Res);
|
||||
break;
|
||||
}
|
||||
case 'D':
|
||||
@@ -3961,6 +4254,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
|
||||
case 'c':
|
||||
First += 2;
|
||||
return make<NameType>("decltype(auto)");
|
||||
// ::= Dk <type-constraint> # constrained auto
|
||||
// ::= DK <type-constraint> # constrained decltype(auto)
|
||||
case 'k':
|
||||
case 'K': {
|
||||
std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)";
|
||||
First += 2;
|
||||
Node *Constraint = getDerived().parseName();
|
||||
if (!Constraint)
|
||||
return nullptr;
|
||||
return make<PostfixQualifiedType>(Constraint, Kind);
|
||||
}
|
||||
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
|
||||
case 'n':
|
||||
First += 2;
|
||||
@@ -4512,6 +4816,75 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
|
||||
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
|
||||
}
|
||||
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseConstraintExpr() {
|
||||
// Within this expression, all enclosing template parameter lists are in
|
||||
// scope.
|
||||
ScopedOverride<bool> SaveInConstraintExpr(InConstraintExpr, true);
|
||||
return getDerived().parseExpr();
|
||||
}
|
||||
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
|
||||
NodeArray Params;
|
||||
if (consumeIf("rQ")) {
|
||||
// <expression> ::= rQ <bare-function-type> _ <requirement>+ E
|
||||
size_t ParamsBegin = Names.size();
|
||||
while (!consumeIf('_')) {
|
||||
Node *Type = getDerived().parseType();
|
||||
if (Type == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(Type);
|
||||
}
|
||||
Params = popTrailingNodeArray(ParamsBegin);
|
||||
} else if (!consumeIf("rq")) {
|
||||
// <expression> ::= rq <requirement>+ E
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t ReqsBegin = Names.size();
|
||||
do {
|
||||
Node *Constraint = nullptr;
|
||||
if (consumeIf('X')) {
|
||||
// <requirement> ::= X <expression> [N] [R <type-constraint>]
|
||||
Node *Expr = getDerived().parseExpr();
|
||||
if (Expr == nullptr)
|
||||
return nullptr;
|
||||
bool Noexcept = consumeIf('N');
|
||||
Node *TypeReq = nullptr;
|
||||
if (consumeIf('R')) {
|
||||
TypeReq = getDerived().parseName();
|
||||
if (TypeReq == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
Constraint = make<ExprRequirement>(Expr, Noexcept, TypeReq);
|
||||
} else if (consumeIf('T')) {
|
||||
// <requirement> ::= T <type>
|
||||
Node *Type = getDerived().parseType();
|
||||
if (Type == nullptr)
|
||||
return nullptr;
|
||||
Constraint = make<TypeRequirement>(Type);
|
||||
} else if (consumeIf('Q')) {
|
||||
// <requirement> ::= Q <constraint-expression>
|
||||
//
|
||||
// FIXME: We use <expression> instead of <constraint-expression>. Either
|
||||
// the requires expression is already inside a constraint expression, in
|
||||
// which case it makes no difference, or we're in a requires-expression
|
||||
// that might be partially-substituted, where the language behavior is
|
||||
// not yet settled and clang mangles after substitution.
|
||||
Node *NestedReq = getDerived().parseExpr();
|
||||
if (NestedReq == nullptr)
|
||||
return nullptr;
|
||||
Constraint = make<NestedRequirement>(NestedReq);
|
||||
}
|
||||
if (Constraint == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(Constraint);
|
||||
} while (!consumeIf('E'));
|
||||
|
||||
return make<RequiresExpr>(Params, popTrailingNodeArray(ReqsBegin));
|
||||
}
|
||||
|
||||
// <expression> ::= <unary operator-name> <expression>
|
||||
// ::= <binary operator-name> <expression> <expression>
|
||||
// ::= <ternary operator-name> <expression> <expression> <expression>
|
||||
@@ -4748,6 +5121,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
|
||||
return Ex;
|
||||
return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
|
||||
}
|
||||
if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q'))
|
||||
return parseRequiresExpr();
|
||||
if (consumeIf("so"))
|
||||
return parseSubobjectExpr();
|
||||
if (consumeIf("sp")) {
|
||||
@@ -5026,29 +5401,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
|
||||
}
|
||||
|
||||
// <encoding> ::= <function name> <bare-function-type>
|
||||
// [`Q` <requires-clause expr>]
|
||||
// ::= <data name>
|
||||
// ::= <special-name>
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) {
|
||||
// The template parameters of an encoding are unrelated to those of the
|
||||
// enclosing context.
|
||||
class SaveTemplateParams {
|
||||
AbstractManglingParser *Parser;
|
||||
decltype(TemplateParams) OldParams;
|
||||
decltype(OuterTemplateParams) OldOuterParams;
|
||||
|
||||
public:
|
||||
SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
|
||||
OldParams = std::move(Parser->TemplateParams);
|
||||
OldOuterParams = std::move(Parser->OuterTemplateParams);
|
||||
Parser->TemplateParams.clear();
|
||||
Parser->OuterTemplateParams.clear();
|
||||
}
|
||||
~SaveTemplateParams() {
|
||||
Parser->TemplateParams = std::move(OldParams);
|
||||
Parser->OuterTemplateParams = std::move(OldOuterParams);
|
||||
}
|
||||
} SaveTemplateParams(this);
|
||||
SaveTemplateParams SaveTemplateParamsScope(this);
|
||||
|
||||
if (look() == 'G' || look() == 'T')
|
||||
return getDerived().parseSpecialName();
|
||||
@@ -5071,6 +5431,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
|
||||
if (IsEndOfEncoding())
|
||||
return Name;
|
||||
|
||||
// ParseParams may be false at the top level only, when called from parse().
|
||||
// For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be
|
||||
// false when demangling 3fooILZ3BarEET_f but is always true when demangling
|
||||
// 3Bar.
|
||||
if (!ParseParams) {
|
||||
while (consume())
|
||||
;
|
||||
return Name;
|
||||
}
|
||||
|
||||
Node *Attrs = nullptr;
|
||||
if (consumeIf("Ua9enable_ifI")) {
|
||||
size_t BeforeArgs = Names.size();
|
||||
@@ -5092,22 +5462,35 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (consumeIf('v'))
|
||||
return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
|
||||
Attrs, NameInfo.CVQualifiers,
|
||||
NameInfo.ReferenceQualifier);
|
||||
NodeArray Params;
|
||||
if (!consumeIf('v')) {
|
||||
size_t ParamsBegin = Names.size();
|
||||
do {
|
||||
Node *Ty = getDerived().parseType();
|
||||
if (Ty == nullptr)
|
||||
return nullptr;
|
||||
|
||||
size_t ParamsBegin = Names.size();
|
||||
do {
|
||||
Node *Ty = getDerived().parseType();
|
||||
if (Ty == nullptr)
|
||||
const bool IsFirstParam = ParamsBegin == Names.size();
|
||||
if (NameInfo.HasExplicitObjectParameter && IsFirstParam)
|
||||
Ty = make<ExplicitObjectParameter>(Ty);
|
||||
|
||||
if (Ty == nullptr)
|
||||
return nullptr;
|
||||
|
||||
Names.push_back(Ty);
|
||||
} while (!IsEndOfEncoding() && look() != 'Q');
|
||||
Params = popTrailingNodeArray(ParamsBegin);
|
||||
}
|
||||
|
||||
Node *Requires = nullptr;
|
||||
if (consumeIf('Q')) {
|
||||
Requires = getDerived().parseConstraintExpr();
|
||||
if (!Requires)
|
||||
return nullptr;
|
||||
Names.push_back(Ty);
|
||||
} while (!IsEndOfEncoding());
|
||||
}
|
||||
|
||||
return make<FunctionEncoding>(ReturnType, Name,
|
||||
popTrailingNodeArray(ParamsBegin),
|
||||
Attrs, NameInfo.CVQualifiers,
|
||||
return make<FunctionEncoding>(ReturnType, Name, Params, Attrs, Requires,
|
||||
NameInfo.CVQualifiers,
|
||||
NameInfo.ReferenceQualifier);
|
||||
}
|
||||
|
||||
@@ -5134,7 +5517,8 @@ template <>
|
||||
struct FloatData<long double>
|
||||
{
|
||||
#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
|
||||
defined(__wasm__) || defined(__riscv) || defined(__loongarch__)
|
||||
defined(__wasm__) || defined(__riscv) || defined(__loongarch__) || \
|
||||
defined(__ve__)
|
||||
static const size_t mangled_size = 32;
|
||||
#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
|
||||
static const size_t mangled_size = 16;
|
||||
@@ -5268,6 +5652,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
|
||||
// ::= TL <level-1> _ <parameter-2 non-negative number> _
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
|
||||
const char *Begin = First;
|
||||
if (!consumeIf('T'))
|
||||
return nullptr;
|
||||
|
||||
@@ -5289,6 +5674,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We don't track enclosing template parameter levels well enough to reliably
|
||||
// substitute them all within a <constraint-expression>, so print the
|
||||
// parameter numbering instead for now.
|
||||
// TODO: Track all enclosing template parameters and substitute them here.
|
||||
if (InConstraintExpr) {
|
||||
return make<NameType>(std::string_view(Begin, First - 1 - Begin));
|
||||
}
|
||||
|
||||
// If we're in a context where this <template-param> refers to a
|
||||
// <template-arg> further ahead in the mangled name (currently just conversion
|
||||
// operator types), then we should only look it up in the right context.
|
||||
@@ -5297,7 +5690,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
|
||||
Node *ForwardRef = make<ForwardTemplateReference>(Index);
|
||||
if (!ForwardRef)
|
||||
return nullptr;
|
||||
assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
|
||||
DEMANGLE_ASSERT(ForwardRef->getKind() == Node::KForwardTemplateReference,
|
||||
"");
|
||||
ForwardTemplateRefs.push_back(
|
||||
static_cast<ForwardTemplateReference *>(ForwardRef));
|
||||
return ForwardRef;
|
||||
@@ -5326,11 +5720,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
|
||||
// ::= Tt <template-param-decl>* E # template parameter
|
||||
// ::= Tp <template-param-decl> # parameter pack
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl(
|
||||
TemplateParamList *Params) {
|
||||
auto InventTemplateParamName = [&](TemplateParamKind Kind) {
|
||||
unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
|
||||
Node *N = make<SyntheticTemplateParamName>(Kind, Index);
|
||||
if (N) TemplateParams.back()->push_back(N);
|
||||
if (N && Params)
|
||||
Params->push_back(N);
|
||||
return N;
|
||||
};
|
||||
|
||||
@@ -5341,6 +5737,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
|
||||
return make<TypeTemplateParamDecl>(Name);
|
||||
}
|
||||
|
||||
if (consumeIf("Tk")) {
|
||||
Node *Constraint = getDerived().parseName();
|
||||
if (!Constraint)
|
||||
return nullptr;
|
||||
Node *Name = InventTemplateParamName(TemplateParamKind::Type);
|
||||
if (!Name)
|
||||
return nullptr;
|
||||
return make<ConstrainedTypeTemplateParamDecl>(Constraint, Name);
|
||||
}
|
||||
|
||||
if (consumeIf("Tn")) {
|
||||
Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
|
||||
if (!Name)
|
||||
@@ -5357,18 +5763,25 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
|
||||
return nullptr;
|
||||
size_t ParamsBegin = Names.size();
|
||||
ScopedTemplateParamList TemplateTemplateParamParams(this);
|
||||
while (!consumeIf("E")) {
|
||||
Node *P = parseTemplateParamDecl();
|
||||
Node *Requires = nullptr;
|
||||
while (!consumeIf('E')) {
|
||||
Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params());
|
||||
if (!P)
|
||||
return nullptr;
|
||||
Names.push_back(P);
|
||||
if (consumeIf('Q')) {
|
||||
Requires = getDerived().parseConstraintExpr();
|
||||
if (Requires == nullptr || !consumeIf('E'))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NodeArray Params = popTrailingNodeArray(ParamsBegin);
|
||||
return make<TemplateTemplateParamDecl>(Name, Params);
|
||||
NodeArray InnerParams = popTrailingNodeArray(ParamsBegin);
|
||||
return make<TemplateTemplateParamDecl>(Name, InnerParams, Requires);
|
||||
}
|
||||
|
||||
if (consumeIf("Tp")) {
|
||||
Node *P = parseTemplateParamDecl();
|
||||
Node *P = parseTemplateParamDecl(Params);
|
||||
if (!P)
|
||||
return nullptr;
|
||||
return make<TemplateParamPackDecl>(P);
|
||||
@@ -5382,6 +5795,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
|
||||
// ::= <expr-primary> # simple expressions
|
||||
// ::= J <template-arg>* E # argument pack
|
||||
// ::= LZ <encoding> E # extension
|
||||
// ::= <template-param-decl> <template-arg>
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
|
||||
switch (look()) {
|
||||
@@ -5416,6 +5830,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
|
||||
// ::= <expr-primary> # simple expressions
|
||||
return getDerived().parseExprPrimary();
|
||||
}
|
||||
case 'T': {
|
||||
// Either <template-param> or a <template-param-decl> <template-arg>.
|
||||
if (!getDerived().isTemplateParamDecl())
|
||||
return getDerived().parseType();
|
||||
Node *Param = getDerived().parseTemplateParamDecl(nullptr);
|
||||
if (!Param)
|
||||
return nullptr;
|
||||
Node *Arg = getDerived().parseTemplateArg();
|
||||
if (!Arg)
|
||||
return nullptr;
|
||||
return make<TemplateParamQualifiedArg>(Param, Arg);
|
||||
}
|
||||
default:
|
||||
return getDerived().parseType();
|
||||
}
|
||||
@@ -5438,30 +5864,39 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
|
||||
}
|
||||
|
||||
size_t ArgsBegin = Names.size();
|
||||
Node *Requires = nullptr;
|
||||
while (!consumeIf('E')) {
|
||||
if (TagTemplates) {
|
||||
auto OldParams = std::move(TemplateParams);
|
||||
Node *Arg = getDerived().parseTemplateArg();
|
||||
TemplateParams = std::move(OldParams);
|
||||
if (Arg == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(Arg);
|
||||
Node *TableEntry = Arg;
|
||||
if (Arg->getKind() == Node::KTemplateParamQualifiedArg) {
|
||||
TableEntry =
|
||||
static_cast<TemplateParamQualifiedArg *>(TableEntry)->getArg();
|
||||
}
|
||||
if (Arg->getKind() == Node::KTemplateArgumentPack) {
|
||||
TableEntry = make<ParameterPack>(
|
||||
static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
|
||||
if (!TableEntry)
|
||||
return nullptr;
|
||||
}
|
||||
TemplateParams.back()->push_back(TableEntry);
|
||||
OuterTemplateParams.push_back(TableEntry);
|
||||
} else {
|
||||
Node *Arg = getDerived().parseTemplateArg();
|
||||
if (Arg == nullptr)
|
||||
return nullptr;
|
||||
Names.push_back(Arg);
|
||||
}
|
||||
if (consumeIf('Q')) {
|
||||
Requires = getDerived().parseConstraintExpr();
|
||||
if (!Requires || !consumeIf('E'))
|
||||
return nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
|
||||
return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin), Requires);
|
||||
}
|
||||
|
||||
// <mangled-name> ::= _Z <encoding>
|
||||
@@ -5470,9 +5905,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
|
||||
// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
|
||||
// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
|
||||
template <typename Derived, typename Alloc>
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parse() {
|
||||
Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) {
|
||||
if (consumeIf("_Z") || consumeIf("__Z")) {
|
||||
Node *Encoding = getDerived().parseEncoding();
|
||||
Node *Encoding = getDerived().parseEncoding(ParseParams);
|
||||
if (Encoding == nullptr)
|
||||
return nullptr;
|
||||
if (look() == '.') {
|
||||
@@ -5486,7 +5921,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() {
|
||||
}
|
||||
|
||||
if (consumeIf("___Z") || consumeIf("____Z")) {
|
||||
Node *Encoding = getDerived().parseEncoding();
|
||||
Node *Encoding = getDerived().parseEncoding(ParseParams);
|
||||
if (Encoding == nullptr || !consumeIf("_block_invoke"))
|
||||
return nullptr;
|
||||
bool RequireNumber = consumeIf('_');
|
||||
|
||||
+9
@@ -19,6 +19,7 @@ NODE(QualType)
|
||||
NODE(ConversionOperatorType)
|
||||
NODE(PostfixQualifiedType)
|
||||
NODE(ElaboratedTypeSpefType)
|
||||
NODE(TransformedType)
|
||||
NODE(NameType)
|
||||
NODE(AbiTagAttr)
|
||||
NODE(EnableIfAttr)
|
||||
@@ -36,6 +37,7 @@ NODE(SpecialName)
|
||||
NODE(CtorVtableSpecialName)
|
||||
NODE(QualifiedName)
|
||||
NODE(NestedName)
|
||||
NODE(MemberLikeFriendName)
|
||||
NODE(LocalName)
|
||||
NODE(ModuleName)
|
||||
NODE(ModuleEntity)
|
||||
@@ -44,7 +46,9 @@ NODE(PixelVectorType)
|
||||
NODE(BinaryFPType)
|
||||
NODE(BitIntType)
|
||||
NODE(SyntheticTemplateParamName)
|
||||
NODE(TemplateParamQualifiedArg)
|
||||
NODE(TypeTemplateParamDecl)
|
||||
NODE(ConstrainedTypeTemplateParamDecl)
|
||||
NODE(NonTypeTemplateParamDecl)
|
||||
NODE(TemplateTemplateParamDecl)
|
||||
NODE(TemplateParamPackDecl)
|
||||
@@ -91,5 +95,10 @@ NODE(DoubleLiteral)
|
||||
NODE(LongDoubleLiteral)
|
||||
NODE(BracedExpr)
|
||||
NODE(BracedRangeExpr)
|
||||
NODE(RequiresExpr)
|
||||
NODE(ExprRequirement)
|
||||
NODE(TypeRequirement)
|
||||
NODE(NestedRequirement)
|
||||
NODE(ExplicitObjectParameter)
|
||||
|
||||
#undef NODE
|
||||
|
||||
Vendored
+3
-5
@@ -19,11 +19,9 @@
|
||||
#include "DemangleConfig.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <limits>
|
||||
#include <string_view>
|
||||
|
||||
@@ -49,7 +47,7 @@ class OutputBuffer {
|
||||
BufferCapacity = Need;
|
||||
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
||||
if (Buffer == nullptr)
|
||||
std::terminate();
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +158,7 @@ public:
|
||||
}
|
||||
|
||||
void insert(size_t Pos, const char *S, size_t N) {
|
||||
assert(Pos <= CurrentPosition);
|
||||
DEMANGLE_ASSERT(Pos <= CurrentPosition, "");
|
||||
if (N == 0)
|
||||
return;
|
||||
grow(N);
|
||||
@@ -173,7 +171,7 @@ public:
|
||||
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||
|
||||
char back() const {
|
||||
assert(CurrentPosition);
|
||||
DEMANGLE_ASSERT(CurrentPosition, "");
|
||||
return Buffer[CurrentPosition - 1];
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "fallback_malloc.h"
|
||||
#include "abort_message.h"
|
||||
|
||||
#include <__threading_support>
|
||||
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||
@@ -16,7 +17,7 @@
|
||||
#endif
|
||||
|
||||
#include <__memory/aligned_alloc.h>
|
||||
#include <assert.h>
|
||||
#include <__assert>
|
||||
#include <stdlib.h> // for malloc, calloc, free
|
||||
#include <string.h> // for memset
|
||||
|
||||
@@ -142,7 +143,7 @@ void* fallback_malloc(size_t len) {
|
||||
|
||||
// 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);
|
||||
_LIBCXXABI_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
|
||||
@@ -163,7 +164,7 @@ void* fallback_malloc(size_t len) {
|
||||
q->next_node = 0;
|
||||
q->len = static_cast<heap_size>(aligned_nelems);
|
||||
void* ptr = q + 1;
|
||||
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
|
||||
_LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -176,7 +177,7 @@ void* fallback_malloc(size_t len) {
|
||||
prev->next_node = p->next_node;
|
||||
p->next_node = 0;
|
||||
void* ptr = p + 1;
|
||||
assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0);
|
||||
_LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, "");
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
+333
-187
@@ -42,6 +42,7 @@
|
||||
// is_equal() with use_strcmp=false so the string names are not compared.
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
@@ -75,6 +76,242 @@ static inline ptrdiff_t update_offset_to_base(const char* vtable,
|
||||
namespace __cxxabiv1
|
||||
{
|
||||
|
||||
namespace {
|
||||
|
||||
struct derived_object_info {
|
||||
const void* dynamic_ptr;
|
||||
const __class_type_info* dynamic_type;
|
||||
std::ptrdiff_t offset_to_derived;
|
||||
};
|
||||
|
||||
/// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr.
|
||||
void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr)
|
||||
{
|
||||
#if __has_feature(cxx_abi_relative_vtable)
|
||||
// The vtable address will point to the first virtual function, which is 8
|
||||
// bytes after the start of the vtable (4 for the offset from top + 4 for
|
||||
// the typeinfo component).
|
||||
const int32_t* vtable =
|
||||
*reinterpret_cast<const int32_t* const*>(static_ptr);
|
||||
info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]);
|
||||
info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
|
||||
|
||||
// The typeinfo component is now a relative offset to a proxy.
|
||||
int32_t offset_to_ti_proxy = vtable[-1];
|
||||
const uint8_t* ptr_to_ti_proxy =
|
||||
reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
|
||||
info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
|
||||
#else
|
||||
void **vtable = *static_cast<void ** const *>(static_ptr);
|
||||
info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
|
||||
info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived;
|
||||
info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// A helper function for __dynamic_cast that casts a base sub-object pointer
|
||||
/// to the object's dynamic type.
|
||||
///
|
||||
/// This function returns the casting result directly. No further processing
|
||||
/// required.
|
||||
///
|
||||
/// Specifically, this function can only be called if the following pre-
|
||||
/// condition holds:
|
||||
/// * The dynamic type of the object pointed to by `static_ptr` is exactly
|
||||
/// the same as `dst_type`.
|
||||
const void* dyn_cast_to_derived(const void* static_ptr,
|
||||
const void* dynamic_ptr,
|
||||
const __class_type_info* static_type,
|
||||
const __class_type_info* dst_type,
|
||||
std::ptrdiff_t offset_to_derived,
|
||||
std::ptrdiff_t src2dst_offset)
|
||||
{
|
||||
// We're downcasting from src_type to the complete object's dynamic type.
|
||||
// This is a really hot path that can be further optimized with the
|
||||
// `src2dst_offset` hint.
|
||||
// In such a case, dynamic_ptr already gives the casting result if the
|
||||
// casting ever succeeds. All we have to do now is to check static_ptr
|
||||
// points to a public base sub-object of dynamic_ptr.
|
||||
|
||||
if (src2dst_offset >= 0)
|
||||
{
|
||||
// The static type is a unique public non-virtual base type of
|
||||
// dst_type at offset `src2dst_offset` from the origin of dst.
|
||||
// Note that there might be other non-public static_type bases. The
|
||||
// hint only guarantees that the public base is non-virtual and
|
||||
// unique. So we have to check whether static_ptr points to that
|
||||
// unique public base sub-object.
|
||||
if (offset_to_derived != -src2dst_offset)
|
||||
return nullptr;
|
||||
return dynamic_ptr;
|
||||
}
|
||||
|
||||
if (src2dst_offset == -2)
|
||||
{
|
||||
// static_type is not a public base of dst_type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If src2dst_offset == -3, then:
|
||||
// src_type is a multiple public base type but never a virtual
|
||||
// base type. We can't conclude that static_ptr points to those
|
||||
// public base sub-objects because there might be other non-
|
||||
// public static_type bases. The search is inevitable.
|
||||
|
||||
// Fallback to the slow path to check that static_type is a public
|
||||
// base type of dynamic_type.
|
||||
// Using giant short cut. Add that information to info.
|
||||
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, // number_of_dst_type
|
||||
false, false, false, true, nullptr};
|
||||
// Do the search
|
||||
dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
|
||||
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// The following if should always be false because we should
|
||||
// definitely find (static_ptr, static_type), either on a public
|
||||
// or private path
|
||||
if (info.path_dst_ptr_to_static_ptr == unknown)
|
||||
{
|
||||
// We get here only if there is some kind of visibility problem
|
||||
// in client code.
|
||||
static_assert(std::atomic<size_t>::is_always_lock_free, "");
|
||||
static std::atomic<size_t> error_count(0);
|
||||
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
|
||||
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
|
||||
"should have public visibility. At least one of them is hidden. %s"
|
||||
", %s.\n", static_type->name(), dst_type->name());
|
||||
// Redo the search comparing type_info's using strcmp
|
||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, false, false, false, true, nullptr};
|
||||
info.number_of_dst_type = 1;
|
||||
dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
|
||||
}
|
||||
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// Query the search.
|
||||
if (info.path_dst_ptr_to_static_ptr != public_path)
|
||||
return nullptr;
|
||||
|
||||
return dynamic_ptr;
|
||||
}
|
||||
|
||||
/// A helper function for __dynamic_cast that tries to perform a downcast
|
||||
/// before giving up and falling back to the slow path.
|
||||
const void* dyn_cast_try_downcast(const void* static_ptr,
|
||||
const void* dynamic_ptr,
|
||||
const __class_type_info* dst_type,
|
||||
const __class_type_info* dynamic_type,
|
||||
std::ptrdiff_t src2dst_offset)
|
||||
{
|
||||
if (src2dst_offset < 0)
|
||||
{
|
||||
// We can only optimize the case if the static type is a unique public
|
||||
// base of dst_type. Give up.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Pretend there is a dst_type object that leads to static_ptr. Later we
|
||||
// will check whether this imagined dst_type object exists. If it exists
|
||||
// then it will be the casting result.
|
||||
const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
|
||||
|
||||
if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr))
|
||||
{
|
||||
// The imagined dst_type object does not exist. Bail-out quickly.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to search a path from dynamic_type to dst_type.
|
||||
__dynamic_cast_info dynamic_to_dst_info = {dynamic_type,
|
||||
dst_ptr_to_static,
|
||||
dst_type,
|
||||
src2dst_offset,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1, // number_of_dst_type
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
nullptr};
|
||||
dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
|
||||
if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
|
||||
// We have found at least one path from dynamic_ptr to dst_ptr. The
|
||||
// downcast can succeed.
|
||||
return dst_ptr_to_static;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const void* dyn_cast_slow(const void* static_ptr,
|
||||
const void* dynamic_ptr,
|
||||
const __class_type_info* static_type,
|
||||
const __class_type_info* dst_type,
|
||||
const __class_type_info* dynamic_type,
|
||||
std::ptrdiff_t src2dst_offset)
|
||||
{
|
||||
// Not using giant short cut. Do the search
|
||||
|
||||
// Initialize info struct for this search.
|
||||
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, false, false, false, true, nullptr};
|
||||
|
||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
|
||||
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// The following if should always be false because we should
|
||||
// definitely find (static_ptr, static_type), either on a public
|
||||
// or private path
|
||||
if (info.path_dst_ptr_to_static_ptr == unknown &&
|
||||
info.path_dynamic_ptr_to_static_ptr == unknown)
|
||||
{
|
||||
static_assert(std::atomic<size_t>::is_always_lock_free, "");
|
||||
static std::atomic<size_t> error_count(0);
|
||||
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
|
||||
syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
|
||||
"has hidden visibility or is defined in more than one translation "
|
||||
"unit. They should all have public visibility. "
|
||||
"%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
|
||||
dst_type->name());
|
||||
// Redo the search comparing type_info's using strcmp
|
||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, false, false, false, true, nullptr};
|
||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
|
||||
}
|
||||
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// Query the search.
|
||||
switch (info.number_to_static_ptr)
|
||||
{
|
||||
case 0:
|
||||
if (info.number_to_dst_ptr == 1 &&
|
||||
info.path_dynamic_ptr_to_static_ptr == public_path &&
|
||||
info.path_dynamic_ptr_to_dst_ptr == public_path)
|
||||
return info.dst_ptr_not_leading_to_static_ptr;
|
||||
break;
|
||||
case 1:
|
||||
if (info.path_dst_ptr_to_static_ptr == public_path ||
|
||||
(
|
||||
info.number_to_dst_ptr == 0 &&
|
||||
info.path_dynamic_ptr_to_static_ptr == public_path &&
|
||||
info.path_dynamic_ptr_to_dst_ptr == public_path
|
||||
)
|
||||
)
|
||||
return info.dst_ptr_leading_to_static_ptr;
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// __shim_type_info
|
||||
|
||||
__shim_type_info::~__shim_type_info()
|
||||
@@ -233,7 +470,8 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
|
||||
if (thrown_class_type == 0)
|
||||
return false;
|
||||
// bullet 2
|
||||
__dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
|
||||
assert(adjustedPtr && "catching a class without an object?");
|
||||
__dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, nullptr};
|
||||
info.number_of_dst_type = 1;
|
||||
thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
|
||||
if (info.path_dst_ptr_to_static_ptr == public_path)
|
||||
@@ -248,32 +486,46 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type,
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
// When we have an object to inspect - we just pass the pointer to the sub-
|
||||
// object that matched the static_type we just checked. If that is different
|
||||
// from any previously recorded pointer to that object type, then we have
|
||||
// an ambiguous case.
|
||||
|
||||
// When we have no object to inspect, we need to account for virtual bases
|
||||
// explicitly.
|
||||
// info->vbase_cookie is a pointer to the name of the innermost virtual base
|
||||
// type, or nullptr if there is no virtual base on the path so far.
|
||||
// adjustedPtr points to the subobject we just found.
|
||||
// If vbase_cookie != any previously recorded (including the case of nullptr
|
||||
// representing an already-found static sub-object) then we have an ambiguous
|
||||
// case. Assuming that the vbase_cookie values agree; if then we have a
|
||||
// different offset (adjustedPtr) from any previously recorded, this indicates
|
||||
// an ambiguous case within the virtual base.
|
||||
|
||||
void
|
||||
__class_type_info::process_found_base_class(__dynamic_cast_info* info,
|
||||
void* adjustedPtr,
|
||||
int path_below) const
|
||||
{
|
||||
if (info->dst_ptr_leading_to_static_ptr == 0)
|
||||
{
|
||||
// First time here
|
||||
info->dst_ptr_leading_to_static_ptr = adjustedPtr;
|
||||
info->path_dst_ptr_to_static_ptr = path_below;
|
||||
info->number_to_static_ptr = 1;
|
||||
}
|
||||
else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
|
||||
{
|
||||
// We've been here before. Update path to "most public"
|
||||
if (info->path_dst_ptr_to_static_ptr == not_public_path)
|
||||
info->path_dst_ptr_to_static_ptr = path_below;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
|
||||
// to a static_type
|
||||
info->number_to_static_ptr += 1;
|
||||
info->path_dst_ptr_to_static_ptr = not_public_path;
|
||||
info->search_done = true;
|
||||
}
|
||||
if (info->number_to_static_ptr == 0) {
|
||||
// First time we found this base
|
||||
info->dst_ptr_leading_to_static_ptr = adjustedPtr;
|
||||
info->path_dst_ptr_to_static_ptr = path_below;
|
||||
// stash the virtual base cookie.
|
||||
info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie;
|
||||
info->number_to_static_ptr = 1;
|
||||
} else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie &&
|
||||
info->dst_ptr_leading_to_static_ptr == adjustedPtr) {
|
||||
// We've been here before. Update path to "most public"
|
||||
if (info->path_dst_ptr_to_static_ptr == not_public_path)
|
||||
info->path_dst_ptr_to_static_ptr = path_below;
|
||||
} else {
|
||||
// We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
|
||||
// to a static_type.
|
||||
info->number_to_static_ptr += 1;
|
||||
info->path_dst_ptr_to_static_ptr = not_public_path;
|
||||
info->search_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -301,16 +553,30 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
|
||||
void* adjustedPtr,
|
||||
int path_below) const
|
||||
{
|
||||
ptrdiff_t offset_to_base = 0;
|
||||
if (adjustedPtr != nullptr)
|
||||
{
|
||||
offset_to_base = __offset_flags >> __offset_shift;
|
||||
if (__offset_flags & __virtual_mask)
|
||||
{
|
||||
const char* vtable = *static_cast<const char*const*>(adjustedPtr);
|
||||
offset_to_base = update_offset_to_base(vtable, offset_to_base);
|
||||
}
|
||||
bool is_virtual = __offset_flags & __virtual_mask;
|
||||
ptrdiff_t offset_to_base = 0;
|
||||
if (info->have_object) {
|
||||
/* We have an object to inspect, we can look through its vtables to
|
||||
find the layout. */
|
||||
offset_to_base = __offset_flags >> __offset_shift;
|
||||
if (is_virtual) {
|
||||
const char* vtable = *static_cast<const char* const*>(adjustedPtr);
|
||||
offset_to_base = update_offset_to_base(vtable, offset_to_base);
|
||||
}
|
||||
} else if (!is_virtual) {
|
||||
/* We have no object; however, for non-virtual bases, (since we do not
|
||||
need to inspect any content) we can pretend to have an object based
|
||||
at '0'. */
|
||||
offset_to_base = __offset_flags >> __offset_shift;
|
||||
} else {
|
||||
/* No object to inspect, and the next base is virtual.
|
||||
We cannot indirect through the vtable to find the actual object offset.
|
||||
So, update vbase_cookie to the new innermost virtual base using the
|
||||
pointer to the typeinfo name as a key. */
|
||||
info->vbase_cookie = static_cast<const void*>(__base_type->name());
|
||||
// .. and reset the pointer.
|
||||
adjustedPtr = nullptr;
|
||||
}
|
||||
__base_type->has_unambiguous_public_base(
|
||||
info,
|
||||
static_cast<char*>(adjustedPtr) + offset_to_base,
|
||||
@@ -431,14 +697,22 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type,
|
||||
dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
|
||||
if (thrown_class_type == 0)
|
||||
return false;
|
||||
__dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
|
||||
bool have_object = adjustedPtr != nullptr;
|
||||
__dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
have_object, nullptr};
|
||||
info.number_of_dst_type = 1;
|
||||
thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
|
||||
if (info.path_dst_ptr_to_static_ptr == public_path)
|
||||
{
|
||||
if (adjustedPtr != NULL)
|
||||
adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
|
||||
return true;
|
||||
// In the case of a thrown null pointer, we have no object but we might
|
||||
// well have computed the offset to where a public sub-object would be.
|
||||
// However, we do not want to return that offset to the user; we still
|
||||
// want them to catch a null ptr.
|
||||
if (have_object)
|
||||
adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
|
||||
else
|
||||
adjustedPtr = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -623,174 +897,46 @@ extern "C" _LIBCXXABI_FUNC_VIS void *
|
||||
__dynamic_cast(const void *static_ptr, const __class_type_info *static_type,
|
||||
const __class_type_info *dst_type,
|
||||
std::ptrdiff_t src2dst_offset) {
|
||||
// Possible future optimization: Take advantage of src2dst_offset
|
||||
|
||||
// Get (dynamic_ptr, dynamic_type) from static_ptr
|
||||
#if __has_feature(cxx_abi_relative_vtable)
|
||||
// The vtable address will point to the first virtual function, which is 8
|
||||
// bytes after the start of the vtable (4 for the offset from top + 4 for the typeinfo component).
|
||||
const int32_t* vtable =
|
||||
*reinterpret_cast<const int32_t* const*>(static_ptr);
|
||||
int32_t offset_to_derived = vtable[-2];
|
||||
const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
|
||||
|
||||
// The typeinfo component is now a relative offset to a proxy.
|
||||
int32_t offset_to_ti_proxy = vtable[-1];
|
||||
const uint8_t* ptr_to_ti_proxy =
|
||||
reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy;
|
||||
const __class_type_info* dynamic_type =
|
||||
*(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy));
|
||||
#else
|
||||
void **vtable = *static_cast<void ** const *>(static_ptr);
|
||||
ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
|
||||
const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
|
||||
const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
|
||||
#endif
|
||||
derived_object_info derived_info;
|
||||
dyn_cast_get_derived_info(&derived_info, static_ptr);
|
||||
|
||||
// Initialize answer to nullptr. This will be changed from the search
|
||||
// results if a non-null answer is found. Regardless, this is what will
|
||||
// be returned.
|
||||
const void* dst_ptr = 0;
|
||||
// Initialize info struct for this search.
|
||||
__dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,};
|
||||
|
||||
// Find out if we can use a giant short cut in the search
|
||||
if (is_equal(dynamic_type, dst_type, false))
|
||||
if (is_equal(derived_info.dynamic_type, dst_type, false))
|
||||
{
|
||||
// We're downcasting from src_type to the complete object's dynamic
|
||||
// type. This is a really hot path that can be further optimized
|
||||
// with the `src2dst_offset` hint.
|
||||
// In such a case, dynamic_ptr already gives the casting result if the
|
||||
// casting ever succeeds. All we have to do now is to check
|
||||
// static_ptr points to a public base sub-object of dynamic_ptr.
|
||||
|
||||
if (src2dst_offset >= 0)
|
||||
{
|
||||
// The static type is a unique public non-virtual base type of
|
||||
// dst_type at offset `src2dst_offset` from the origin of dst.
|
||||
// Note that there might be other non-public static_type bases. The
|
||||
// hint only guarantees that the public base is non-virtual and
|
||||
// unique. So we have to check whether static_ptr points to that
|
||||
// unique public base sub-object.
|
||||
if (offset_to_derived == -src2dst_offset)
|
||||
dst_ptr = dynamic_ptr;
|
||||
}
|
||||
else if (src2dst_offset == -2)
|
||||
{
|
||||
// static_type is not a public base of dst_type.
|
||||
dst_ptr = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If src2dst_offset == -3, then:
|
||||
// src_type is a multiple public base type but never a virtual
|
||||
// base type. We can't conclude that static_ptr points to those
|
||||
// public base sub-objects because there might be other non-
|
||||
// public static_type bases. The search is inevitable.
|
||||
|
||||
// Fallback to the slow path to check that static_type is a public
|
||||
// base type of dynamic_type.
|
||||
// Using giant short cut. Add that information to info.
|
||||
info.number_of_dst_type = 1;
|
||||
// Do the search
|
||||
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false);
|
||||
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// The following if should always be false because we should
|
||||
// definitely find (static_ptr, static_type), either on a public
|
||||
// or private path
|
||||
if (info.path_dst_ptr_to_static_ptr == unknown)
|
||||
{
|
||||
// We get here only if there is some kind of visibility problem
|
||||
// in client code.
|
||||
static_assert(std::atomic<size_t>::is_always_lock_free, "");
|
||||
static std::atomic<size_t> error_count(0);
|
||||
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
|
||||
syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's "
|
||||
"should have public visibility. At least one of them is hidden. %s"
|
||||
", %s.\n", static_type->name(), dynamic_type->name());
|
||||
// Redo the search comparing type_info's using strcmp
|
||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
|
||||
info.number_of_dst_type = 1;
|
||||
dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true);
|
||||
}
|
||||
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// Query the search.
|
||||
if (info.path_dst_ptr_to_static_ptr == public_path)
|
||||
dst_ptr = dynamic_ptr;
|
||||
}
|
||||
dst_ptr = dyn_cast_to_derived(static_ptr,
|
||||
derived_info.dynamic_ptr,
|
||||
static_type,
|
||||
dst_type,
|
||||
derived_info.offset_to_derived,
|
||||
src2dst_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src2dst_offset >= 0)
|
||||
{
|
||||
// Optimize toward downcasting: dst_type has one unique public
|
||||
// static_type bases. Let's first try to do a downcast before
|
||||
// falling back to the slow path. The downcast succeeds if there
|
||||
// is at least one path regardless of visibility from
|
||||
// dynamic_type to dst_type.
|
||||
const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset;
|
||||
if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) >= reinterpret_cast<std::intptr_t>(dynamic_ptr))
|
||||
{
|
||||
// Try to search a path from dynamic_type to dst_type.
|
||||
__dynamic_cast_info dynamic_to_dst_info = {dynamic_type, dst_ptr_to_static, dst_type, src2dst_offset};
|
||||
dynamic_to_dst_info.number_of_dst_type = 1;
|
||||
dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false);
|
||||
if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) {
|
||||
// We have found at least one path from dynamic_ptr to
|
||||
// dst_ptr. The downcast can succeed.
|
||||
dst_ptr = dst_ptr_to_static;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Optimize toward downcasting: let's first try to do a downcast before
|
||||
// falling back to the slow path.
|
||||
dst_ptr = dyn_cast_try_downcast(static_ptr,
|
||||
derived_info.dynamic_ptr,
|
||||
dst_type,
|
||||
derived_info.dynamic_type,
|
||||
src2dst_offset);
|
||||
|
||||
if (!dst_ptr)
|
||||
{
|
||||
// Not using giant short cut. Do the search
|
||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false);
|
||||
#ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// The following if should always be false because we should
|
||||
// definitely find (static_ptr, static_type), either on a public
|
||||
// or private path
|
||||
if (info.path_dst_ptr_to_static_ptr == unknown &&
|
||||
info.path_dynamic_ptr_to_static_ptr == unknown)
|
||||
{
|
||||
static_assert(std::atomic<size_t>::is_always_lock_free, "");
|
||||
static std::atomic<size_t> error_count(0);
|
||||
size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if ((error_count_snapshot & (error_count_snapshot-1)) == 0)
|
||||
syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's "
|
||||
"has hidden visibility or is defined in more than one translation "
|
||||
"unit. They should all have public visibility. "
|
||||
"%s, %s, %s.\n", static_type->name(), dynamic_type->name(),
|
||||
dst_type->name());
|
||||
// Redo the search comparing type_info's using strcmp
|
||||
info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
|
||||
dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true);
|
||||
}
|
||||
#endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST
|
||||
// Query the search.
|
||||
switch (info.number_to_static_ptr)
|
||||
{
|
||||
case 0:
|
||||
if (info.number_to_dst_ptr == 1 &&
|
||||
info.path_dynamic_ptr_to_static_ptr == public_path &&
|
||||
info.path_dynamic_ptr_to_dst_ptr == public_path)
|
||||
dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
|
||||
break;
|
||||
case 1:
|
||||
if (info.path_dst_ptr_to_static_ptr == public_path ||
|
||||
(
|
||||
info.number_to_dst_ptr == 0 &&
|
||||
info.path_dynamic_ptr_to_static_ptr == public_path &&
|
||||
info.path_dynamic_ptr_to_dst_ptr == public_path
|
||||
)
|
||||
)
|
||||
dst_ptr = info.dst_ptr_leading_to_static_ptr;
|
||||
break;
|
||||
}
|
||||
dst_ptr = dyn_cast_slow(static_ptr,
|
||||
derived_info.dynamic_ptr,
|
||||
static_type,
|
||||
dst_type,
|
||||
derived_info.dynamic_type,
|
||||
src2dst_offset);
|
||||
}
|
||||
}
|
||||
|
||||
return const_cast<void*>(dst_ptr);
|
||||
}
|
||||
|
||||
@@ -1075,7 +1221,7 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
|
||||
if (info->search_done)
|
||||
break;
|
||||
// If we just found a dst_type with a public path to (static_ptr, static_type),
|
||||
// then the only reason to continue the search is to make sure sure
|
||||
// then the only reason to continue the search is to make sure
|
||||
// no other dst_type points to (static_ptr, static_type).
|
||||
// If !diamond, then we don't need to search here.
|
||||
// if we just found a dst_type with a private path to (static_ptr, static_type),
|
||||
|
||||
Vendored
+7
@@ -110,6 +110,13 @@ struct _LIBCXXABI_HIDDEN __dynamic_cast_info
|
||||
bool found_any_static_type;
|
||||
// Set whenever a search can be stopped
|
||||
bool search_done;
|
||||
|
||||
// Data that modifies the search mechanism.
|
||||
|
||||
// There is no object (seen when we throw a null pointer to object).
|
||||
bool have_object;
|
||||
// Virtual base
|
||||
const void* vbase_cookie;
|
||||
};
|
||||
|
||||
// Has no base class
|
||||
|
||||
+173
-195
@@ -7,7 +7,10 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "__cxxabi_config.h"
|
||||
#include "abort_message.h"
|
||||
#include "include/overridable_function.h" // from libc++
|
||||
#include <__memory/aligned_alloc.h>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
|
||||
@@ -25,241 +28,216 @@
|
||||
# error libc++ and libc++abi seem to disagree on whether exceptions are enabled
|
||||
#endif
|
||||
|
||||
inline void __throw_bad_alloc_shim() {
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
abort_message("bad_alloc was thrown in -fno-exceptions mode");
|
||||
#endif
|
||||
}
|
||||
|
||||
#define _LIBCPP_ASSERT_SHIM(expr, str) \
|
||||
do { \
|
||||
if (!expr) \
|
||||
abort_message(str); \
|
||||
} while (false)
|
||||
|
||||
// ------------------ BEGIN COPY ------------------
|
||||
// Implement all new and delete operators as weak definitions
|
||||
// in this shared library, so that they can be overridden by programs
|
||||
// that define non-weak copies of the functions.
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void *
|
||||
operator new(std::size_t size) _THROW_BAD_ALLOC
|
||||
{
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
void* p;
|
||||
while ((p = std::malloc(size)) == nullptr)
|
||||
{
|
||||
// If malloc fails and there is a new_handler,
|
||||
// call it to try free up memory.
|
||||
std::new_handler nh = std::get_new_handler();
|
||||
if (nh)
|
||||
nh();
|
||||
else
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
throw std::bad_alloc();
|
||||
static void* operator_new_impl(std::size_t size) {
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
void* p;
|
||||
while ((p = std::malloc(size)) == nullptr) {
|
||||
// If malloc fails and there is a new_handler,
|
||||
// call it to try free up memory.
|
||||
std::new_handler nh = std::get_new_handler();
|
||||
if (nh)
|
||||
nh();
|
||||
else
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_impl(size);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept {
|
||||
#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, "
|
||||
"but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case "
|
||||
"it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its "
|
||||
"contract (since it should return nullptr upon failure). Please make sure you override "
|
||||
"`operator new(size_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_impl(size);
|
||||
#else
|
||||
break;
|
||||
void* p = nullptr;
|
||||
try {
|
||||
p = ::operator new(size);
|
||||
} catch (...) {
|
||||
}
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new(size_t size, const std::nothrow_t&) noexcept
|
||||
{
|
||||
void* p = nullptr;
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
p = ::operator new(size);
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
return p;
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new[](size_t size) _THROW_BAD_ALLOC
|
||||
{
|
||||
return ::operator new(size);
|
||||
_LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept {
|
||||
#ifdef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, "
|
||||
"but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case "
|
||||
"it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its "
|
||||
"contract (since it should return nullptr upon failure). Please make sure you override "
|
||||
"`operator new[](size_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_impl(size);
|
||||
#else
|
||||
void* p = nullptr;
|
||||
try {
|
||||
p = ::operator new[](size);
|
||||
} catch (...) {
|
||||
}
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new[](size_t size, const std::nothrow_t&) noexcept
|
||||
{
|
||||
void* p = nullptr;
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
p = ::operator new[](size);
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
return p;
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); }
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr) noexcept
|
||||
{
|
||||
std::free(ptr);
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); }
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr, const std::nothrow_t&) noexcept
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); }
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr, size_t) noexcept
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); }
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr) noexcept
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); }
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr, const std::nothrow_t&) noexcept
|
||||
{
|
||||
::operator delete[](ptr);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr, size_t) noexcept
|
||||
{
|
||||
::operator delete[](ptr);
|
||||
}
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); }
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void *
|
||||
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
|
||||
{
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
if (static_cast<size_t>(alignment) < sizeof(void*))
|
||||
alignment = std::align_val_t(sizeof(void*));
|
||||
static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
if (static_cast<size_t>(alignment) < sizeof(void*))
|
||||
alignment = std::align_val_t(sizeof(void*));
|
||||
|
||||
// Try allocating memory. If allocation fails and there is a new_handler,
|
||||
// call it to try free up memory, and try again until it succeeds, or until
|
||||
// the new_handler decides to terminate.
|
||||
//
|
||||
// If allocation fails and there is no new_handler, we throw bad_alloc
|
||||
// (or return nullptr if exceptions are disabled).
|
||||
void* p;
|
||||
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr)
|
||||
{
|
||||
std::new_handler nh = std::get_new_handler();
|
||||
if (nh)
|
||||
nh();
|
||||
else {
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
throw std::bad_alloc();
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return p;
|
||||
// Try allocating memory. If allocation fails and there is a new_handler,
|
||||
// call it to try free up memory, and try again until it succeeds, or until
|
||||
// the new_handler decides to terminate.
|
||||
void* p;
|
||||
while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) {
|
||||
std::new_handler nh = std::get_new_handler();
|
||||
if (nh)
|
||||
nh();
|
||||
else
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||
{
|
||||
void* p = nullptr;
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
p = ::operator new(size, alignment);
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
return p;
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
void* p = operator_new_aligned_impl(size, alignment);
|
||||
if (p == nullptr)
|
||||
__throw_bad_alloc_shim();
|
||||
return p;
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC
|
||||
{
|
||||
return ::operator new(size, alignment);
|
||||
_LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
# ifdef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)),
|
||||
"libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will "
|
||||
"terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` "
|
||||
"to fulfill its contract (since it should return nullptr upon failure). Please make sure you override "
|
||||
"`operator new(size_t, align_val_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_aligned_impl(size, alignment);
|
||||
# else
|
||||
void* p = nullptr;
|
||||
try {
|
||||
p = ::operator new(size, alignment);
|
||||
} catch (...) {
|
||||
}
|
||||
return p;
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void*
|
||||
operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||
{
|
||||
void* p = nullptr;
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
p = ::operator new[](size, alignment);
|
||||
#ifndef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
#endif // _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
return p;
|
||||
_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void*
|
||||
operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC {
|
||||
return ::operator new(size, alignment);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr, std::align_val_t) noexcept
|
||||
{
|
||||
std::__libcpp_aligned_free(ptr);
|
||||
_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
# ifdef _LIBCPP_HAS_NO_EXCEPTIONS
|
||||
# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION
|
||||
_LIBCPP_ASSERT_SHIM(
|
||||
!std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])),
|
||||
"libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, "
|
||||
"but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will "
|
||||
"terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, "
|
||||
"nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you "
|
||||
"override "
|
||||
"`operator new[](size_t, align_val_t, nothrow_t)` as well.");
|
||||
# endif
|
||||
|
||||
return operator_new_aligned_impl(size, alignment);
|
||||
# else
|
||||
void* p = nullptr;
|
||||
try {
|
||||
p = ::operator new[](size, alignment);
|
||||
} catch (...) {
|
||||
}
|
||||
return p;
|
||||
# endif
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||
{
|
||||
::operator delete(ptr, alignment);
|
||||
_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); }
|
||||
|
||||
_LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
::operator delete(ptr, alignment);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept
|
||||
{
|
||||
::operator delete(ptr, alignment);
|
||||
_LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept {
|
||||
::operator delete(ptr, alignment);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr, std::align_val_t alignment) noexcept
|
||||
{
|
||||
::operator delete(ptr, alignment);
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept {
|
||||
::operator delete(ptr, alignment);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept
|
||||
{
|
||||
::operator delete[](ptr, alignment);
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
::operator delete[](ptr, alignment);
|
||||
}
|
||||
|
||||
_LIBCPP_WEAK
|
||||
void
|
||||
operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept
|
||||
{
|
||||
::operator delete[](ptr, alignment);
|
||||
_LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept {
|
||||
::operator delete[](ptr, alignment);
|
||||
}
|
||||
|
||||
#endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION
|
||||
|
||||
Reference in New Issue
Block a user