| author | |
| committer | |
| log | bc6ebc6f2597fda1f98842c6f545751fef2a5334 |
| tree | 7fe57a76daad5c2ea3c0f429c04d8ef861baaf32 |
| parent | 6295415da72eb17b263494a070fdf957e89460fb |
release/18.x branch, commit 78b99c73ee4b96fe9ce0e294d4632326afb2db4218 files changed, 1181 insertions(+), 555 deletions(-)
lib/libcxxabi/include/cxxabi.h+11| ... | ... | @@ -36,6 +36,9 @@ class type_info; // forward declaration |
| 36 | 36 | |
| 37 | 37 | // runtime routines use C calling conventions, but are in __cxxabiv1 namespace |
| 38 | 38 | namespace __cxxabiv1 { |
| 39 | ||
| 40 | struct __cxa_exception; | |
| 41 | ||
| 39 | 42 | extern "C" { |
| 40 | 43 | |
| 41 | 44 | // 2.4.2 Allocating the Exception Object |
| ... | ... | @@ -43,11 +46,19 @@ extern _LIBCXXABI_FUNC_VIS void * |
| 43 | 46 | __cxa_allocate_exception(size_t thrown_size) throw(); |
| 44 | 47 | extern _LIBCXXABI_FUNC_VIS void |
| 45 | 48 | __cxa_free_exception(void *thrown_exception) throw(); |
| 49 | // This function is an LLVM extension, which mirrors the same extension in libsupc++ and libcxxrt | |
| 50 | extern _LIBCXXABI_FUNC_VIS __cxa_exception* | |
| 51 | __cxa_init_primary_exception(void* object, std::type_info* tinfo, void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw(); | |
| 46 | 52 | |
| 47 | 53 | // 2.4.3 Throwing the Exception Object |
| 48 | 54 | extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void |
| 49 | 55 | __cxa_throw(void *thrown_exception, std::type_info *tinfo, |
| 56 | #ifdef __USING_WASM_EXCEPTIONS__ | |
| 57 | // In Wasm, a destructor returns its argument | |
| 58 | void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)); | |
| 59 | #else | |
| 50 | 60 | void (_LIBCXXABI_DTOR_FUNC *dest)(void *)); |
| 61 | #endif | |
| 51 | 62 | |
| 52 | 63 | // 2.5.3 Exception Handlers |
| 53 | 64 | extern _LIBCXXABI_FUNC_VIS void * |
lib/libcxxabi/src/abort_message.h+11| ... | ... | @@ -14,4 +14,15 @@ |
| 14 | 14 | extern "C" _LIBCXXABI_HIDDEN _LIBCXXABI_NORETURN void |
| 15 | 15 | abort_message(const char *format, ...) __attribute__((format(printf, 1, 2))); |
| 16 | 16 | |
| 17 | #ifndef _LIBCXXABI_ASSERT | |
| 18 | # define _LIBCXXABI_ASSERT(expr, msg) \ | |
| 19 | do { \ | |
| 20 | if (!(expr)) { \ | |
| 21 | char const* __msg = (msg); \ | |
| 22 | ::abort_message("%s:%d: %s", __FILE__, __LINE__, __msg); \ | |
| 23 | } \ | |
| 24 | } while (false) | |
| 25 | ||
| 17 | 26 | #endif |
| 27 | ||
| 28 | #endif // __ABORT_MESSAGE_H_ |
lib/libcxxabi/src/aix_state_tab_eh.inc+1-1| ... | ... | @@ -740,6 +740,6 @@ __catchThrownException(void (*cdfunc)(void), // function which may fail |
| 740 | 740 | return 0; |
| 741 | 741 | } |
| 742 | 742 | |
| 743 | } // extern "C" | |
| 743 | } // extern "C" | |
| 744 | 744 | |
| 745 | 745 | } // __cxxabiv1 |
lib/libcxxabi/src/cxa_demangle.cpp+5-2| ... | ... | @@ -10,14 +10,17 @@ |
| 10 | 10 | // file does not yet support: |
| 11 | 11 | // - C++ modules TS |
| 12 | 12 | |
| 13 | #include "abort_message.h" | |
| 14 | #define DEMANGLE_ASSERT(expr, msg) _LIBCXXABI_ASSERT(expr, msg) | |
| 15 | ||
| 13 | 16 | #include "demangle/DemangleConfig.h" |
| 14 | 17 | #include "demangle/ItaniumDemangle.h" |
| 15 | 18 | #include "__cxxabi_config.h" |
| 16 | #include <cassert> | |
| 17 | 19 | #include <cctype> |
| 18 | 20 | #include <cstdio> |
| 19 | 21 | #include <cstdlib> |
| 20 | 22 | #include <cstring> |
| 23 | #include <exception> | |
| 21 | 24 | #include <functional> |
| 22 | 25 | #include <numeric> |
| 23 | 26 | #include <string_view> |
| ... | ... | @@ -394,7 +397,7 @@ __cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) { |
| 394 | 397 | InternalStatus = demangle_invalid_mangled_name; |
| 395 | 398 | else { |
| 396 | 399 | OutputBuffer O(Buf, N); |
| 397 | assert(Parser.ForwardTemplateRefs.empty()); | |
| 400 | DEMANGLE_ASSERT(Parser.ForwardTemplateRefs.empty(), ""); | |
| 398 | 401 | AST->print(O); |
| 399 | 402 | O += '\0'; |
| 400 | 403 | if (N != nullptr) |
lib/libcxxabi/src/cxa_exception.cpp+25-14| ... | ... | @@ -206,6 +206,19 @@ void __cxa_free_exception(void *thrown_object) throw() { |
| 206 | 206 | __aligned_free_with_fallback((void *)raw_buffer); |
| 207 | 207 | } |
| 208 | 208 | |
| 209 | __cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, | |
| 210 | void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { | |
| 211 | __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); | |
| 212 | exception_header->referenceCount = 0; | |
| 213 | exception_header->unexpectedHandler = std::get_unexpected(); | |
| 214 | exception_header->terminateHandler = std::get_terminate(); | |
| 215 | exception_header->exceptionType = tinfo; | |
| 216 | exception_header->exceptionDestructor = dest; | |
| 217 | setOurExceptionClass(&exception_header->unwindHeader); | |
| 218 | exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; | |
| 219 | ||
| 220 | return exception_header; | |
| 221 | } | |
| 209 | 222 | |
| 210 | 223 | // This function shall allocate a __cxa_dependent_exception and |
| 211 | 224 | // 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 |
| 254 | 267 | exception. |
| 255 | 268 | */ |
| 256 | 269 | void |
| 270 | #ifdef __USING_WASM_EXCEPTIONS__ | |
| 271 | // In Wasm, a destructor returns its argument | |
| 272 | __cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)) { | |
| 273 | #else | |
| 257 | 274 | __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { |
| 258 | __cxa_eh_globals *globals = __cxa_get_globals(); | |
| 259 | __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); | |
| 260 | ||
| 261 | exception_header->unexpectedHandler = std::get_unexpected(); | |
| 262 | exception_header->terminateHandler = std::get_terminate(); | |
| 263 | exception_header->exceptionType = tinfo; | |
| 264 | exception_header->exceptionDestructor = dest; | |
| 265 | setOurExceptionClass(&exception_header->unwindHeader); | |
| 266 | exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. | |
| 267 | globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local | |
| 275 | #endif | |
| 276 | __cxa_eh_globals* globals = __cxa_get_globals(); | |
| 277 | globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local | |
| 268 | 278 | |
| 269 | exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; | |
| 279 | __cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest); | |
| 280 | exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. | |
| 270 | 281 | |
| 271 | 282 | #if __has_feature(address_sanitizer) |
| 272 | // Inform the ASan runtime that now might be a good time to clean stuff up. | |
| 273 | __asan_handle_no_return(); | |
| 283 | // Inform the ASan runtime that now might be a good time to clean stuff up. | |
| 284 | __asan_handle_no_return(); | |
| 274 | 285 | #endif |
| 275 | 286 | |
| 276 | 287 | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| ... | ... | @@ -771,6 +782,6 @@ __cxa_uncaught_exceptions() throw() |
| 771 | 782 | return globals->uncaughtExceptions; |
| 772 | 783 | } |
| 773 | 784 | |
| 774 | } // extern "C" | |
| 785 | } // extern "C" | |
| 775 | 786 | |
| 776 | 787 | } // abi |
lib/libcxxabi/src/cxa_exception.h+5| ... | ... | @@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { |
| 43 | 43 | |
| 44 | 44 | // Manage the exception object itself. |
| 45 | 45 | std::type_info *exceptionType; |
| 46 | #ifdef __USING_WASM_EXCEPTIONS__ | |
| 47 | // In Wasm, a destructor returns its argument | |
| 48 | void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); | |
| 49 | #else | |
| 46 | 50 | void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *); |
| 51 | #endif | |
| 47 | 52 | std::unexpected_handler unexpectedHandler; |
| 48 | 53 | std::terminate_handler terminateHandler; |
| 49 | 54 |
lib/libcxxabi/src/cxa_guard.cpp+1-1| ... | ... | @@ -48,6 +48,6 @@ _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) { |
| 48 | 48 | SelectedImplementation imp(raw_guard_object); |
| 49 | 49 | imp.cxa_guard_abort(); |
| 50 | 50 | } |
| 51 | } // extern "C" | |
| 51 | } // extern "C" | |
| 52 | 52 | |
| 53 | 53 | } // __cxxabiv1 |
lib/libcxxabi/src/cxa_noexception.cpp+1-1| ... | ... | @@ -49,7 +49,7 @@ __cxa_uncaught_exception() throw() { return false; } |
| 49 | 49 | unsigned int |
| 50 | 50 | __cxa_uncaught_exceptions() throw() { return 0; } |
| 51 | 51 | |
| 52 | } // extern "C" | |
| 52 | } // extern "C" | |
| 53 | 53 | |
| 54 | 54 | // provide dummy implementations for the 'no exceptions' case. |
| 55 | 55 | uint64_t __getExceptionClass (const _Unwind_Exception*) { return 0; } |
lib/libcxxabi/src/cxa_personality.cpp+29-23| ... | ... | @@ -70,7 +70,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, |
| 70 | 70 | +------------------+--+-----+-----+------------------------+--------------------------+ |
| 71 | 71 | | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | |
| 72 | 72 | +---------------------+-----------+---------------------------------------------------+ |
| 73 | #ifndef __USING_SJLJ_EXCEPTIONS__ | |
| 73 | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) | |
| 74 | 74 | +---------------------+-----------+------------------------------------------------+ |
| 75 | 75 | | Beginning of Call Site Table The current ip lies within the | |
| 76 | 76 | | ... (start, length) range of one of these | |
| ... | ... | @@ -84,7 +84,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, |
| 84 | 84 | | +-------------+---------------------------------+------------------------------+ | |
| 85 | 85 | | ... | |
| 86 | 86 | +----------------------------------------------------------------------------------+ |
| 87 | #else // __USING_SJLJ_EXCEPTIONS__ | |
| 87 | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 88 | 88 | +---------------------+-----------+------------------------------------------------+ |
| 89 | 89 | | Beginning of Call Site Table The current ip is a 1-based index into | |
| 90 | 90 | | ... this table. Or it is -1 meaning no | |
| ... | ... | @@ -97,7 +97,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, |
| 97 | 97 | | +-------------+---------------------------------+------------------------------+ | |
| 98 | 98 | | ... | |
| 99 | 99 | +----------------------------------------------------------------------------------+ |
| 100 | #endif // __USING_SJLJ_EXCEPTIONS__ | |
| 100 | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 101 | 101 | +---------------------------------------------------------------------+ |
| 102 | 102 | | Beginning of Action Table ttypeIndex == 0 : cleanup | |
| 103 | 103 | | ... ttypeIndex > 0 : catch | |
| ... | ... | @@ -547,7 +547,7 @@ void |
| 547 | 547 | set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, |
| 548 | 548 | const scan_results& results) |
| 549 | 549 | { |
| 550 | #if defined(__USING_SJLJ_EXCEPTIONS__) | |
| 550 | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) | |
| 551 | 551 | #define __builtin_eh_return_data_regno(regno) regno |
| 552 | 552 | #elif defined(__ibmxl__) |
| 553 | 553 | // 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, |
| 642 | 642 | // Get beginning current frame's code (as defined by the |
| 643 | 643 | // emitted dwarf code) |
| 644 | 644 | uintptr_t funcStart = _Unwind_GetRegionStart(context); |
| 645 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 645 | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) | |
| 646 | 646 | if (ip == uintptr_t(-1)) |
| 647 | 647 | { |
| 648 | 648 | // no action |
| ... | ... | @@ -652,18 +652,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 652 | 652 | else if (ip == 0) |
| 653 | 653 | call_terminate(native_exception, unwind_exception); |
| 654 | 654 | // ip is 1-based index into call site table |
| 655 | #else // !__USING_SJLJ_EXCEPTIONS__ | |
| 655 | #else // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ | |
| 656 | 656 | uintptr_t ipOffset = ip - funcStart; |
| 657 | #endif // !defined(_USING_SLJL_EXCEPTIONS__) | |
| 657 | #endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ | |
| 658 | 658 | const uint8_t* classInfo = NULL; |
| 659 | 659 | // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding |
| 660 | 660 | // dwarf emission |
| 661 | 661 | // Parse LSDA header. |
| 662 | 662 | uint8_t lpStartEncoding = *lsda++; |
| 663 | const uint8_t* lpStart = | |
| 664 | (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); | |
| 665 | if (lpStart == 0) | |
| 666 | lpStart = (const uint8_t*)funcStart; | |
| 663 | const uint8_t* lpStart = lpStartEncoding == DW_EH_PE_omit | |
| 664 | ? (const uint8_t*)funcStart | |
| 665 | : (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding, base); | |
| 667 | 666 | uint8_t ttypeEncoding = *lsda++; |
| 668 | 667 | if (ttypeEncoding != DW_EH_PE_omit) |
| 669 | 668 | { |
| ... | ... | @@ -676,8 +675,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 676 | 675 | // Walk call-site table looking for range that |
| 677 | 676 | // includes current PC. |
| 678 | 677 | uint8_t callSiteEncoding = *lsda++; |
| 679 | #ifdef __USING_SJLJ_EXCEPTIONS__ | |
| 680 | (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used | |
| 678 | #if defined(__USING_SJLJ_EXCEPTIONS__) || defined(__USING_WASM_EXCEPTIONS__) | |
| 679 | (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used | |
| 681 | 680 | #endif |
| 682 | 681 | uint32_t callSiteTableLength = static_cast<uint32_t>(readULEB128(&lsda)); |
| 683 | 682 | const uint8_t* callSiteTableStart = lsda; |
| ... | ... | @@ -687,7 +686,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 687 | 686 | while (callSitePtr < callSiteTableEnd) |
| 688 | 687 | { |
| 689 | 688 | // There is one entry per call site. |
| 690 | #ifndef __USING_SJLJ_EXCEPTIONS__ | |
| 689 | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) | |
| 691 | 690 | // The call sites are non-overlapping in [start, start+length) |
| 692 | 691 | // The call sites are ordered in increasing value of start |
| 693 | 692 | uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); |
| ... | ... | @@ -695,15 +694,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 695 | 694 | uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); |
| 696 | 695 | uintptr_t actionEntry = readULEB128(&callSitePtr); |
| 697 | 696 | if ((start <= ipOffset) && (ipOffset < (start + length))) |
| 698 | #else // __USING_SJLJ_EXCEPTIONS__ | |
| 697 | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 699 | 698 | // ip is 1-based index into this table |
| 700 | 699 | uintptr_t landingPad = readULEB128(&callSitePtr); |
| 701 | 700 | uintptr_t actionEntry = readULEB128(&callSitePtr); |
| 702 | 701 | if (--ip == 0) |
| 703 | #endif // __USING_SJLJ_EXCEPTIONS__ | |
| 702 | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 704 | 703 | { |
| 705 | 704 | // Found the call site containing ip. |
| 706 | #ifndef __USING_SJLJ_EXCEPTIONS__ | |
| 705 | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) | |
| 707 | 706 | if (landingPad == 0) |
| 708 | 707 | { |
| 709 | 708 | // No handler here |
| ... | ... | @@ -711,9 +710,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 711 | 710 | return; |
| 712 | 711 | } |
| 713 | 712 | landingPad = (uintptr_t)lpStart + landingPad; |
| 714 | #else // __USING_SJLJ_EXCEPTIONS__ | |
| 713 | #else // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 715 | 714 | ++landingPad; |
| 716 | #endif // __USING_SJLJ_EXCEPTIONS__ | |
| 715 | #endif // __USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ | |
| 717 | 716 | results.landingPad = landingPad; |
| 718 | 717 | if (actionEntry == 0) |
| 719 | 718 | { |
| ... | ... | @@ -841,7 +840,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 841 | 840 | action += actionOffset; |
| 842 | 841 | } // there is no break out of this loop, only return |
| 843 | 842 | } |
| 844 | #ifndef __USING_SJLJ_EXCEPTIONS__ | |
| 843 | #if !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__USING_WASM_EXCEPTIONS__) | |
| 845 | 844 | else if (ipOffset < start) |
| 846 | 845 | { |
| 847 | 846 | // There is no call site for this ip |
| ... | ... | @@ -849,7 +848,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, |
| 849 | 848 | // Possible stack corruption. |
| 850 | 849 | call_terminate(native_exception, unwind_exception); |
| 851 | 850 | } |
| 852 | #endif // !__USING_SJLJ_EXCEPTIONS__ | |
| 851 | #endif // !__USING_SJLJ_EXCEPTIONS__ && !__USING_WASM_EXCEPTIONS__ | |
| 853 | 852 | } // there might be some tricky cases which break out of this loop |
| 854 | 853 | |
| 855 | 854 | // It is possible that no eh table entry specify how to handle |
| ... | ... | @@ -906,7 +905,9 @@ _UA_CLEANUP_PHASE |
| 906 | 905 | */ |
| 907 | 906 | |
| 908 | 907 | #if !defined(_LIBCXXABI_ARM_EHABI) |
| 909 | #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 908 | #ifdef __USING_WASM_EXCEPTIONS__ | |
| 909 | _Unwind_Reason_Code __gxx_personality_wasm0 | |
| 910 | #elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) | |
| 910 | 911 | static _Unwind_Reason_Code __gxx_personality_imp |
| 911 | 912 | #else |
| 912 | 913 | _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code |
| ... | ... | @@ -973,6 +974,11 @@ __gxx_personality_v0 |
| 973 | 974 | exc->languageSpecificData = results.languageSpecificData; |
| 974 | 975 | exc->catchTemp = reinterpret_cast<void*>(results.landingPad); |
| 975 | 976 | exc->adjustedPtr = results.adjustedPtr; |
| 977 | #ifdef __USING_WASM_EXCEPTIONS__ | |
| 978 | // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the | |
| 979 | // results here. | |
| 980 | set_registers(unwind_exception, context, results); | |
| 981 | #endif | |
| 976 | 982 | } |
| 977 | 983 | return _URC_HANDLER_FOUND; |
| 978 | 984 | } |
| ... | ... | @@ -1304,7 +1310,7 @@ _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code __xlcxx_personality_v1( |
| 1304 | 1310 | __attribute__((__alias__("__gxx_personality_v0"))); |
| 1305 | 1311 | #endif |
| 1306 | 1312 | |
| 1307 | } // extern "C" | |
| 1313 | } // extern "C" | |
| 1308 | 1314 | |
| 1309 | 1315 | } // __cxxabiv1 |
| 1310 | 1316 |
lib/libcxxabi/src/cxa_vector.cpp+1-1| ... | ... | @@ -416,6 +416,6 @@ __cxa_vec_delete3(void *array_address, size_t element_size, size_t padding_size, |
| 416 | 416 | } |
| 417 | 417 | |
| 418 | 418 | |
| 419 | } // extern "C" | |
| 419 | } // extern "C" | |
| 420 | 420 | |
| 421 | 421 | } // abi |
lib/libcxxabi/src/demangle/DemangleConfig.h+6-1| ... | ... | @@ -19,7 +19,7 @@ |
| 19 | 19 | #include "../abort_message.h" |
| 20 | 20 | #endif |
| 21 | 21 | |
| 22 | #include <ciso646> | |
| 22 | #include <version> | |
| 23 | 23 | |
| 24 | 24 | #ifdef _MSC_VER |
| 25 | 25 | // snprintf is implemented in VS 2015 |
| ... | ... | @@ -99,6 +99,11 @@ |
| 99 | 99 | #define DEMANGLE_FALLTHROUGH |
| 100 | 100 | #endif |
| 101 | 101 | |
| 102 | #ifndef DEMANGLE_ASSERT | |
| 103 | #include <cassert> | |
| 104 | #define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg)) | |
| 105 | #endif | |
| 106 | ||
| 102 | 107 | #define DEMANGLE_NAMESPACE_BEGIN namespace { namespace itanium_demangle { |
| 103 | 108 | #define DEMANGLE_NAMESPACE_END } } |
| 104 | 109 |
lib/libcxxabi/src/demangle/ItaniumDemangle.h+538-103| ... | ... | @@ -21,7 +21,6 @@ |
| 21 | 21 | #include "Utility.h" |
| 22 | 22 | #include <__cxxabi_config.h> |
| 23 | 23 | #include <algorithm> |
| 24 | #include <cassert> | |
| 25 | 24 | #include <cctype> |
| 26 | 25 | #include <cstdio> |
| 27 | 26 | #include <cstdlib> |
| ... | ... | @@ -61,13 +60,13 @@ template <class T, size_t N> class PODSmallVector { |
| 61 | 60 | if (isInline()) { |
| 62 | 61 | auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T))); |
| 63 | 62 | if (Tmp == nullptr) |
| 64 | std::terminate(); | |
| 63 | std::abort(); | |
| 65 | 64 | std::copy(First, Last, Tmp); |
| 66 | 65 | First = Tmp; |
| 67 | 66 | } else { |
| 68 | 67 | First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T))); |
| 69 | 68 | if (First == nullptr) |
| 70 | std::terminate(); | |
| 69 | std::abort(); | |
| 71 | 70 | } |
| 72 | 71 | Last = First + S; |
| 73 | 72 | Cap = First + NewCap; |
| ... | ... | @@ -129,12 +128,12 @@ public: |
| 129 | 128 | |
| 130 | 129 | // NOLINTNEXTLINE(readability-identifier-naming) |
| 131 | 130 | void pop_back() { |
| 132 | assert(Last != First && "Popping empty vector!"); | |
| 131 | DEMANGLE_ASSERT(Last != First, "Popping empty vector!"); | |
| 133 | 132 | --Last; |
| 134 | 133 | } |
| 135 | 134 | |
| 136 | void dropBack(size_t Index) { | |
| 137 | assert(Index <= size() && "dropBack() can't expand!"); | |
| 135 | void shrinkToSize(size_t Index) { | |
| 136 | DEMANGLE_ASSERT(Index <= size(), "shrinkToSize() can't expand!"); | |
| 138 | 137 | Last = First + Index; |
| 139 | 138 | } |
| 140 | 139 | |
| ... | ... | @@ -144,11 +143,11 @@ public: |
| 144 | 143 | bool empty() const { return First == Last; } |
| 145 | 144 | size_t size() const { return static_cast<size_t>(Last - First); } |
| 146 | 145 | T &back() { |
| 147 | assert(Last != First && "Calling back() on empty vector!"); | |
| 146 | DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!"); | |
| 148 | 147 | return *(Last - 1); |
| 149 | 148 | } |
| 150 | 149 | T &operator[](size_t Index) { |
| 151 | assert(Index < size() && "Invalid access!"); | |
| 150 | DEMANGLE_ASSERT(Index < size(), "Invalid access!"); | |
| 152 | 151 | return *(begin() + Index); |
| 153 | 152 | } |
| 154 | 153 | void clear() { Last = First; } |
| ... | ... | @@ -534,6 +533,23 @@ public: |
| 534 | 533 | } |
| 535 | 534 | }; |
| 536 | 535 | |
| 536 | class TransformedType : public Node { | |
| 537 | std::string_view Transform; | |
| 538 | Node *BaseType; | |
| 539 | public: | |
| 540 | TransformedType(std::string_view Transform_, Node *BaseType_) | |
| 541 | : Node(KTransformedType), Transform(Transform_), BaseType(BaseType_) {} | |
| 542 | ||
| 543 | template<typename Fn> void match(Fn F) const { F(Transform, BaseType); } | |
| 544 | ||
| 545 | void printLeft(OutputBuffer &OB) const override { | |
| 546 | OB += Transform; | |
| 547 | OB += '('; | |
| 548 | BaseType->print(OB); | |
| 549 | OB += ')'; | |
| 550 | } | |
| 551 | }; | |
| 552 | ||
| 537 | 553 | struct AbiTagAttr : Node { |
| 538 | 554 | Node *Base; |
| 539 | 555 | std::string_view Tag; |
| ... | ... | @@ -873,26 +889,53 @@ public: |
| 873 | 889 | } |
| 874 | 890 | }; |
| 875 | 891 | |
| 892 | /// Represents the explicitly named object parameter. | |
| 893 | /// E.g., | |
| 894 | /// \code{.cpp} | |
| 895 | /// struct Foo { | |
| 896 | /// void bar(this Foo && self); | |
| 897 | /// }; | |
| 898 | /// \endcode | |
| 899 | class ExplicitObjectParameter final : public Node { | |
| 900 | Node *Base; | |
| 901 | ||
| 902 | public: | |
| 903 | ExplicitObjectParameter(Node *Base_) | |
| 904 | : Node(KExplicitObjectParameter), Base(Base_) { | |
| 905 | DEMANGLE_ASSERT( | |
| 906 | Base != nullptr, | |
| 907 | "Creating an ExplicitObjectParameter without a valid Base Node."); | |
| 908 | } | |
| 909 | ||
| 910 | template <typename Fn> void match(Fn F) const { F(Base); } | |
| 911 | ||
| 912 | void printLeft(OutputBuffer &OB) const override { | |
| 913 | OB += "this "; | |
| 914 | Base->print(OB); | |
| 915 | } | |
| 916 | }; | |
| 917 | ||
| 876 | 918 | class FunctionEncoding final : public Node { |
| 877 | 919 | const Node *Ret; |
| 878 | 920 | const Node *Name; |
| 879 | 921 | NodeArray Params; |
| 880 | 922 | const Node *Attrs; |
| 923 | const Node *Requires; | |
| 881 | 924 | Qualifiers CVQuals; |
| 882 | 925 | FunctionRefQual RefQual; |
| 883 | 926 | |
| 884 | 927 | public: |
| 885 | 928 | FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, |
| 886 | const Node *Attrs_, Qualifiers CVQuals_, | |
| 887 | FunctionRefQual RefQual_) | |
| 929 | const Node *Attrs_, const Node *Requires_, | |
| 930 | Qualifiers CVQuals_, FunctionRefQual RefQual_) | |
| 888 | 931 | : Node(KFunctionEncoding, |
| 889 | 932 | /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, |
| 890 | 933 | /*FunctionCache=*/Cache::Yes), |
| 891 | 934 | Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), |
| 892 | CVQuals(CVQuals_), RefQual(RefQual_) {} | |
| 935 | Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {} | |
| 893 | 936 | |
| 894 | 937 | template<typename Fn> void match(Fn F) const { |
| 895 | F(Ret, Name, Params, Attrs, CVQuals, RefQual); | |
| 938 | F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual); | |
| 896 | 939 | } |
| 897 | 940 | |
| 898 | 941 | Qualifiers getCVQuals() const { return CVQuals; } |
| ... | ... | @@ -935,6 +978,11 @@ public: |
| 935 | 978 | |
| 936 | 979 | if (Attrs != nullptr) |
| 937 | 980 | Attrs->print(OB); |
| 981 | ||
| 982 | if (Requires != nullptr) { | |
| 983 | OB += " requires "; | |
| 984 | Requires->print(OB); | |
| 985 | } | |
| 938 | 986 | } |
| 939 | 987 | }; |
| 940 | 988 | |
| ... | ... | @@ -1006,6 +1054,24 @@ struct NestedName : Node { |
| 1006 | 1054 | } |
| 1007 | 1055 | }; |
| 1008 | 1056 | |
| 1057 | struct MemberLikeFriendName : Node { | |
| 1058 | Node *Qual; | |
| 1059 | Node *Name; | |
| 1060 | ||
| 1061 | MemberLikeFriendName(Node *Qual_, Node *Name_) | |
| 1062 | : Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {} | |
| 1063 | ||
| 1064 | template<typename Fn> void match(Fn F) const { F(Qual, Name); } | |
| 1065 | ||
| 1066 | std::string_view getBaseName() const override { return Name->getBaseName(); } | |
| 1067 | ||
| 1068 | void printLeft(OutputBuffer &OB) const override { | |
| 1069 | Qual->print(OB); | |
| 1070 | OB += "::friend "; | |
| 1071 | Name->print(OB); | |
| 1072 | } | |
| 1073 | }; | |
| 1074 | ||
| 1009 | 1075 | struct ModuleName : Node { |
| 1010 | 1076 | ModuleName *Parent; |
| 1011 | 1077 | Node *Name; |
| ... | ... | @@ -1171,6 +1237,24 @@ public: |
| 1171 | 1237 | } |
| 1172 | 1238 | }; |
| 1173 | 1239 | |
| 1240 | class TemplateParamQualifiedArg final : public Node { | |
| 1241 | Node *Param; | |
| 1242 | Node *Arg; | |
| 1243 | ||
| 1244 | public: | |
| 1245 | TemplateParamQualifiedArg(Node *Param_, Node *Arg_) | |
| 1246 | : Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {} | |
| 1247 | ||
| 1248 | template <typename Fn> void match(Fn F) const { F(Param, Arg); } | |
| 1249 | ||
| 1250 | Node *getArg() { return Arg; } | |
| 1251 | ||
| 1252 | void printLeft(OutputBuffer &OB) const override { | |
| 1253 | // Don't print Param to keep the output consistent. | |
| 1254 | Arg->print(OB); | |
| 1255 | } | |
| 1256 | }; | |
| 1257 | ||
| 1174 | 1258 | /// A template type parameter declaration, 'typename T'. |
| 1175 | 1259 | class TypeTemplateParamDecl final : public Node { |
| 1176 | 1260 | Node *Name; |
| ... | ... | @@ -1186,6 +1270,26 @@ public: |
| 1186 | 1270 | void printRight(OutputBuffer &OB) const override { Name->print(OB); } |
| 1187 | 1271 | }; |
| 1188 | 1272 | |
| 1273 | /// A constrained template type parameter declaration, 'C<U> T'. | |
| 1274 | class ConstrainedTypeTemplateParamDecl final : public Node { | |
| 1275 | Node *Constraint; | |
| 1276 | Node *Name; | |
| 1277 | ||
| 1278 | public: | |
| 1279 | ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_) | |
| 1280 | : Node(KConstrainedTypeTemplateParamDecl, Cache::Yes), | |
| 1281 | Constraint(Constraint_), Name(Name_) {} | |
| 1282 | ||
| 1283 | template<typename Fn> void match(Fn F) const { F(Constraint, Name); } | |
| 1284 | ||
| 1285 | void printLeft(OutputBuffer &OB) const override { | |
| 1286 | Constraint->print(OB); | |
| 1287 | OB += " "; | |
| 1288 | } | |
| 1289 | ||
| 1290 | void printRight(OutputBuffer &OB) const override { Name->print(OB); } | |
| 1291 | }; | |
| 1292 | ||
| 1189 | 1293 | /// A non-type template parameter declaration, 'int N'. |
| 1190 | 1294 | class NonTypeTemplateParamDecl final : public Node { |
| 1191 | 1295 | Node *Name; |
| ... | ... | @@ -1214,13 +1318,14 @@ public: |
| 1214 | 1318 | class TemplateTemplateParamDecl final : public Node { |
| 1215 | 1319 | Node *Name; |
| 1216 | 1320 | NodeArray Params; |
| 1321 | Node *Requires; | |
| 1217 | 1322 | |
| 1218 | 1323 | public: |
| 1219 | TemplateTemplateParamDecl(Node *Name_, NodeArray Params_) | |
| 1324 | TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_) | |
| 1220 | 1325 | : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_), |
| 1221 | Params(Params_) {} | |
| 1326 | Params(Params_), Requires(Requires_) {} | |
| 1222 | 1327 | |
| 1223 | template<typename Fn> void match(Fn F) const { F(Name, Params); } | |
| 1328 | template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); } | |
| 1224 | 1329 | |
| 1225 | 1330 | void printLeft(OutputBuffer &OB) const override { |
| 1226 | 1331 | ScopedOverride<unsigned> LT(OB.GtIsGt, 0); |
| ... | ... | @@ -1229,7 +1334,13 @@ public: |
| 1229 | 1334 | OB += "> typename "; |
| 1230 | 1335 | } |
| 1231 | 1336 | |
| 1232 | void printRight(OutputBuffer &OB) const override { Name->print(OB); } | |
| 1337 | void printRight(OutputBuffer &OB) const override { | |
| 1338 | Name->print(OB); | |
| 1339 | if (Requires != nullptr) { | |
| 1340 | OB += " requires "; | |
| 1341 | Requires->print(OB); | |
| 1342 | } | |
| 1343 | } | |
| 1233 | 1344 | }; |
| 1234 | 1345 | |
| 1235 | 1346 | /// A template parameter pack declaration, 'typename ...T'. |
| ... | ... | @@ -1326,7 +1437,7 @@ public: |
| 1326 | 1437 | |
| 1327 | 1438 | /// A variadic template argument. This node represents an occurrence of |
| 1328 | 1439 | /// J<something>E in some <template-args>. It isn't itself unexpanded, unless |
| 1329 | /// one of it's Elements is. The parser inserts a ParameterPack into the | |
| 1440 | /// one of its Elements is. The parser inserts a ParameterPack into the | |
| 1330 | 1441 | /// TemplateParams table if the <template-args> this pack belongs to apply to an |
| 1331 | 1442 | /// <encoding>. |
| 1332 | 1443 | class TemplateArgumentPack final : public Node { |
| ... | ... | @@ -1392,11 +1503,13 @@ public: |
| 1392 | 1503 | |
| 1393 | 1504 | class TemplateArgs final : public Node { |
| 1394 | 1505 | NodeArray Params; |
| 1506 | Node *Requires; | |
| 1395 | 1507 | |
| 1396 | 1508 | public: |
| 1397 | TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} | |
| 1509 | TemplateArgs(NodeArray Params_, Node *Requires_) | |
| 1510 | : Node(KTemplateArgs), Params(Params_), Requires(Requires_) {} | |
| 1398 | 1511 | |
| 1399 | template<typename Fn> void match(Fn F) const { F(Params); } | |
| 1512 | template<typename Fn> void match(Fn F) const { F(Params, Requires); } | |
| 1400 | 1513 | |
| 1401 | 1514 | NodeArray getParams() { return Params; } |
| 1402 | 1515 | |
| ... | ... | @@ -1405,6 +1518,7 @@ public: |
| 1405 | 1518 | OB += "<"; |
| 1406 | 1519 | Params.printWithComma(OB); |
| 1407 | 1520 | OB += ">"; |
| 1521 | // Don't print the requires clause to keep the output simple. | |
| 1408 | 1522 | } |
| 1409 | 1523 | }; |
| 1410 | 1524 | |
| ... | ... | @@ -1589,7 +1703,7 @@ public: |
| 1589 | 1703 | std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); |
| 1590 | 1704 | if (isInstantiation()) { |
| 1591 | 1705 | // The instantiations are typedefs that drop the "basic_" prefix. |
| 1592 | assert(starts_with(SV, "basic_")); | |
| 1706 | DEMANGLE_ASSERT(starts_with(SV, "basic_"), ""); | |
| 1593 | 1707 | SV.remove_prefix(sizeof("basic_") - 1); |
| 1594 | 1708 | } |
| 1595 | 1709 | return SV; |
| ... | ... | @@ -1655,17 +1769,21 @@ public: |
| 1655 | 1769 | |
| 1656 | 1770 | class ClosureTypeName : public Node { |
| 1657 | 1771 | NodeArray TemplateParams; |
| 1772 | const Node *Requires1; | |
| 1658 | 1773 | NodeArray Params; |
| 1774 | const Node *Requires2; | |
| 1659 | 1775 | std::string_view Count; |
| 1660 | 1776 | |
| 1661 | 1777 | public: |
| 1662 | ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, | |
| 1778 | ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_, | |
| 1779 | NodeArray Params_, const Node *Requires2_, | |
| 1663 | 1780 | std::string_view Count_) |
| 1664 | 1781 | : Node(KClosureTypeName), TemplateParams(TemplateParams_), |
| 1665 | Params(Params_), Count(Count_) {} | |
| 1782 | Requires1(Requires1_), Params(Params_), Requires2(Requires2_), | |
| 1783 | Count(Count_) {} | |
| 1666 | 1784 | |
| 1667 | 1785 | template<typename Fn> void match(Fn F) const { |
| 1668 | F(TemplateParams, Params, Count); | |
| 1786 | F(TemplateParams, Requires1, Params, Requires2, Count); | |
| 1669 | 1787 | } |
| 1670 | 1788 | |
| 1671 | 1789 | void printDeclarator(OutputBuffer &OB) const { |
| ... | ... | @@ -1675,12 +1793,22 @@ public: |
| 1675 | 1793 | TemplateParams.printWithComma(OB); |
| 1676 | 1794 | OB += ">"; |
| 1677 | 1795 | } |
| 1796 | if (Requires1 != nullptr) { | |
| 1797 | OB += " requires "; | |
| 1798 | Requires1->print(OB); | |
| 1799 | OB += " "; | |
| 1800 | } | |
| 1678 | 1801 | OB.printOpen(); |
| 1679 | 1802 | Params.printWithComma(OB); |
| 1680 | 1803 | OB.printClose(); |
| 1804 | if (Requires2 != nullptr) { | |
| 1805 | OB += " requires "; | |
| 1806 | Requires2->print(OB); | |
| 1807 | } | |
| 1681 | 1808 | } |
| 1682 | 1809 | |
| 1683 | 1810 | void printLeft(OutputBuffer &OB) const override { |
| 1811 | // FIXME: This demangling is not particularly readable. | |
| 1684 | 1812 | OB += "\'lambda"; |
| 1685 | 1813 | OB += Count; |
| 1686 | 1814 | OB += "\'"; |
| ... | ... | @@ -2309,6 +2437,95 @@ public: |
| 2309 | 2437 | } |
| 2310 | 2438 | }; |
| 2311 | 2439 | |
| 2440 | class RequiresExpr : public Node { | |
| 2441 | NodeArray Parameters; | |
| 2442 | NodeArray Requirements; | |
| 2443 | public: | |
| 2444 | RequiresExpr(NodeArray Parameters_, NodeArray Requirements_) | |
| 2445 | : Node(KRequiresExpr), Parameters(Parameters_), | |
| 2446 | Requirements(Requirements_) {} | |
| 2447 | ||
| 2448 | template<typename Fn> void match(Fn F) const { F(Parameters, Requirements); } | |
| 2449 | ||
| 2450 | void printLeft(OutputBuffer &OB) const override { | |
| 2451 | OB += "requires"; | |
| 2452 | if (!Parameters.empty()) { | |
| 2453 | OB += ' '; | |
| 2454 | OB.printOpen(); | |
| 2455 | Parameters.printWithComma(OB); | |
| 2456 | OB.printClose(); | |
| 2457 | } | |
| 2458 | OB += ' '; | |
| 2459 | OB.printOpen('{'); | |
| 2460 | for (const Node *Req : Requirements) { | |
| 2461 | Req->print(OB); | |
| 2462 | } | |
| 2463 | OB += ' '; | |
| 2464 | OB.printClose('}'); | |
| 2465 | } | |
| 2466 | }; | |
| 2467 | ||
| 2468 | class ExprRequirement : public Node { | |
| 2469 | const Node *Expr; | |
| 2470 | bool IsNoexcept; | |
| 2471 | const Node *TypeConstraint; | |
| 2472 | public: | |
| 2473 | ExprRequirement(const Node *Expr_, bool IsNoexcept_, | |
| 2474 | const Node *TypeConstraint_) | |
| 2475 | : Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_), | |
| 2476 | TypeConstraint(TypeConstraint_) {} | |
| 2477 | ||
| 2478 | template <typename Fn> void match(Fn F) const { | |
| 2479 | F(Expr, IsNoexcept, TypeConstraint); | |
| 2480 | } | |
| 2481 | ||
| 2482 | void printLeft(OutputBuffer &OB) const override { | |
| 2483 | OB += " "; | |
| 2484 | if (IsNoexcept || TypeConstraint) | |
| 2485 | OB.printOpen('{'); | |
| 2486 | Expr->print(OB); | |
| 2487 | if (IsNoexcept || TypeConstraint) | |
| 2488 | OB.printClose('}'); | |
| 2489 | if (IsNoexcept) | |
| 2490 | OB += " noexcept"; | |
| 2491 | if (TypeConstraint) { | |
| 2492 | OB += " -> "; | |
| 2493 | TypeConstraint->print(OB); | |
| 2494 | } | |
| 2495 | OB += ';'; | |
| 2496 | } | |
| 2497 | }; | |
| 2498 | ||
| 2499 | class TypeRequirement : public Node { | |
| 2500 | const Node *Type; | |
| 2501 | public: | |
| 2502 | TypeRequirement(const Node *Type_) | |
| 2503 | : Node(KTypeRequirement), Type(Type_) {} | |
| 2504 | ||
| 2505 | template <typename Fn> void match(Fn F) const { F(Type); } | |
| 2506 | ||
| 2507 | void printLeft(OutputBuffer &OB) const override { | |
| 2508 | OB += " typename "; | |
| 2509 | Type->print(OB); | |
| 2510 | OB += ';'; | |
| 2511 | } | |
| 2512 | }; | |
| 2513 | ||
| 2514 | class NestedRequirement : public Node { | |
| 2515 | const Node *Constraint; | |
| 2516 | public: | |
| 2517 | NestedRequirement(const Node *Constraint_) | |
| 2518 | : Node(KNestedRequirement), Constraint(Constraint_) {} | |
| 2519 | ||
| 2520 | template <typename Fn> void match(Fn F) const { F(Constraint); } | |
| 2521 | ||
| 2522 | void printLeft(OutputBuffer &OB) const override { | |
| 2523 | OB += " requires "; | |
| 2524 | Constraint->print(OB); | |
| 2525 | OB += ';'; | |
| 2526 | } | |
| 2527 | }; | |
| 2528 | ||
| 2312 | 2529 | template <class Float> struct FloatData; |
| 2313 | 2530 | |
| 2314 | 2531 | namespace float_literal_impl { |
| ... | ... | @@ -2377,7 +2594,7 @@ void Node::visit(Fn F) const { |
| 2377 | 2594 | return F(static_cast<const X *>(this)); |
| 2378 | 2595 | #include "ItaniumNodes.def" |
| 2379 | 2596 | } |
| 2380 | assert(0 && "unknown mangling node kind"); | |
| 2597 | DEMANGLE_ASSERT(0, "unknown mangling node kind"); | |
| 2381 | 2598 | } |
| 2382 | 2599 | |
| 2383 | 2600 | /// Determine the kind of a node from its type. |
| ... | ... | @@ -2403,6 +2620,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2403 | 2620 | // table. |
| 2404 | 2621 | PODSmallVector<Node *, 32> Subs; |
| 2405 | 2622 | |
| 2623 | // A list of template argument values corresponding to a template parameter | |
| 2624 | // list. | |
| 2406 | 2625 | using TemplateParamList = PODSmallVector<Node *, 8>; |
| 2407 | 2626 | |
| 2408 | 2627 | class ScopedTemplateParamList { |
| ... | ... | @@ -2417,9 +2636,11 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2417 | 2636 | Parser->TemplateParams.push_back(&Params); |
| 2418 | 2637 | } |
| 2419 | 2638 | ~ScopedTemplateParamList() { |
| 2420 | assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists); | |
| 2421 | Parser->TemplateParams.dropBack(OldNumTemplateParamLists); | |
| 2639 | DEMANGLE_ASSERT(Parser->TemplateParams.size() >= OldNumTemplateParamLists, | |
| 2640 | ""); | |
| 2641 | Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists); | |
| 2422 | 2642 | } |
| 2643 | TemplateParamList *params() { return &Params; } | |
| 2423 | 2644 | }; |
| 2424 | 2645 | |
| 2425 | 2646 | // Template parameter table. Like the above, but referenced like "T42_". |
| ... | ... | @@ -2434,12 +2655,31 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2434 | 2655 | // parameter list, the corresponding parameter list pointer will be null. |
| 2435 | 2656 | PODSmallVector<TemplateParamList *, 4> TemplateParams; |
| 2436 | 2657 | |
| 2658 | class SaveTemplateParams { | |
| 2659 | AbstractManglingParser *Parser; | |
| 2660 | decltype(TemplateParams) OldParams; | |
| 2661 | decltype(OuterTemplateParams) OldOuterParams; | |
| 2662 | ||
| 2663 | public: | |
| 2664 | SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { | |
| 2665 | OldParams = std::move(Parser->TemplateParams); | |
| 2666 | OldOuterParams = std::move(Parser->OuterTemplateParams); | |
| 2667 | Parser->TemplateParams.clear(); | |
| 2668 | Parser->OuterTemplateParams.clear(); | |
| 2669 | } | |
| 2670 | ~SaveTemplateParams() { | |
| 2671 | Parser->TemplateParams = std::move(OldParams); | |
| 2672 | Parser->OuterTemplateParams = std::move(OldOuterParams); | |
| 2673 | } | |
| 2674 | }; | |
| 2675 | ||
| 2437 | 2676 | // Set of unresolved forward <template-param> references. These can occur in a |
| 2438 | 2677 | // conversion operator's type, and are resolved in the enclosing <encoding>. |
| 2439 | 2678 | PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; |
| 2440 | 2679 | |
| 2441 | 2680 | bool TryToParseTemplateArgs = true; |
| 2442 | 2681 | bool PermitForwardTemplateReferences = false; |
| 2682 | bool InConstraintExpr = false; | |
| 2443 | 2683 | size_t ParsingLambdaParamsAtLevel = (size_t)-1; |
| 2444 | 2684 | |
| 2445 | 2685 | unsigned NumSyntheticTemplateParameters[3] = {}; |
| ... | ... | @@ -2478,10 +2718,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2478 | 2718 | } |
| 2479 | 2719 | |
| 2480 | 2720 | NodeArray popTrailingNodeArray(size_t FromPosition) { |
| 2481 | assert(FromPosition <= Names.size()); | |
| 2721 | DEMANGLE_ASSERT(FromPosition <= Names.size(), ""); | |
| 2482 | 2722 | NodeArray res = |
| 2483 | 2723 | makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); |
| 2484 | Names.dropBack(FromPosition); | |
| 2724 | Names.shrinkToSize(FromPosition); | |
| 2485 | 2725 | return res; |
| 2486 | 2726 | } |
| 2487 | 2727 | |
| ... | ... | @@ -2519,11 +2759,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2519 | 2759 | bool parseSeqId(size_t *Out); |
| 2520 | 2760 | Node *parseSubstitution(); |
| 2521 | 2761 | Node *parseTemplateParam(); |
| 2522 | Node *parseTemplateParamDecl(); | |
| 2762 | Node *parseTemplateParamDecl(TemplateParamList *Params); | |
| 2523 | 2763 | Node *parseTemplateArgs(bool TagTemplates = false); |
| 2524 | 2764 | Node *parseTemplateArg(); |
| 2525 | 2765 | |
| 2526 | /// Parse the <expr> production. | |
| 2766 | bool isTemplateParamDecl() { | |
| 2767 | return look() == 'T' && | |
| 2768 | std::string_view("yptnk").find(look(1)) != std::string_view::npos; | |
| 2769 | } | |
| 2770 | ||
| 2771 | /// Parse the <expression> production. | |
| 2527 | 2772 | Node *parseExpr(); |
| 2528 | 2773 | Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); |
| 2529 | 2774 | Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); |
| ... | ... | @@ -2536,6 +2781,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2536 | 2781 | Node *parseFoldExpr(); |
| 2537 | 2782 | Node *parsePointerToMemberConversionExpr(Node::Prec Prec); |
| 2538 | 2783 | Node *parseSubobjectExpr(); |
| 2784 | Node *parseConstraintExpr(); | |
| 2785 | Node *parseRequiresExpr(); | |
| 2539 | 2786 | |
| 2540 | 2787 | /// Parse the <type> production. |
| 2541 | 2788 | Node *parseType(); |
| ... | ... | @@ -2547,7 +2794,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2547 | 2794 | Node *parseClassEnumType(); |
| 2548 | 2795 | Node *parseQualifiedType(); |
| 2549 | 2796 | |
| 2550 | Node *parseEncoding(); | |
| 2797 | Node *parseEncoding(bool ParseParams = true); | |
| 2551 | 2798 | bool parseCallOffset(); |
| 2552 | 2799 | Node *parseSpecialName(); |
| 2553 | 2800 | |
| ... | ... | @@ -2559,6 +2806,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2559 | 2806 | Qualifiers CVQualifiers = QualNone; |
| 2560 | 2807 | FunctionRefQual ReferenceQualifier = FrefQualNone; |
| 2561 | 2808 | size_t ForwardTemplateRefsBegin; |
| 2809 | bool HasExplicitObjectParameter = false; | |
| 2562 | 2810 | |
| 2563 | 2811 | NameState(AbstractManglingParser *Enclosing) |
| 2564 | 2812 | : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} |
| ... | ... | @@ -2574,7 +2822,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2574 | 2822 | return true; |
| 2575 | 2823 | ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx]; |
| 2576 | 2824 | } |
| 2577 | ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); | |
| 2825 | ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin); | |
| 2578 | 2826 | return false; |
| 2579 | 2827 | } |
| 2580 | 2828 | |
| ... | ... | @@ -2638,8 +2886,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2638 | 2886 | std::string_view getSymbol() const { |
| 2639 | 2887 | std::string_view Res = Name; |
| 2640 | 2888 | if (Kind < Unnameable) { |
| 2641 | assert(starts_with(Res, "operator") && | |
| 2642 | "operator name does not start with 'operator'"); | |
| 2889 | DEMANGLE_ASSERT(starts_with(Res, "operator"), | |
| 2890 | "operator name does not start with 'operator'"); | |
| 2643 | 2891 | Res.remove_prefix(sizeof("operator") - 1); |
| 2644 | 2892 | if (starts_with(Res, ' ')) |
| 2645 | 2893 | Res.remove_prefix(1); |
| ... | ... | @@ -2663,7 +2911,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { |
| 2663 | 2911 | Node *parseDestructorName(); |
| 2664 | 2912 | |
| 2665 | 2913 | /// Top-level entry point into the parser. |
| 2666 | Node *parse(); | |
| 2914 | Node *parse(bool ParseParams = true); | |
| 2667 | 2915 | }; |
| 2668 | 2916 | |
| 2669 | 2917 | const char* parse_discriminator(const char* first, const char* last); |
| ... | ... | @@ -2727,6 +2975,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) { |
| 2727 | 2975 | return make<LocalName>(Encoding, StringLitName); |
| 2728 | 2976 | } |
| 2729 | 2977 | |
| 2978 | // The template parameters of the inner name are unrelated to those of the | |
| 2979 | // enclosing context. | |
| 2980 | SaveTemplateParams SaveTemplateParamsScope(this); | |
| 2981 | ||
| 2730 | 2982 | if (consumeIf('d')) { |
| 2731 | 2983 | parseNumber(true); |
| 2732 | 2984 | if (!consumeIf('_')) |
| ... | ... | @@ -2782,9 +3034,9 @@ AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State, |
| 2782 | 3034 | return Res; |
| 2783 | 3035 | } |
| 2784 | 3036 | |
| 2785 | // <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>] | |
| 3037 | // <unqualified-name> ::= [<module-name>] F? L? <operator-name> [<abi-tags>] | |
| 2786 | 3038 | // ::= [<module-name>] <ctor-dtor-name> [<abi-tags>] |
| 2787 | // ::= [<module-name>] L? <source-name> [<abi-tags>] | |
| 3039 | // ::= [<module-name>] F? L? <source-name> [<abi-tags>] | |
| 2788 | 3040 | // ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>] |
| 2789 | 3041 | //			# structured binding declaration |
| 2790 | 3042 | // ::= [<module-name>] L? DC <source-name>+ E |
| ... | ... | @@ -2794,6 +3046,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName( |
| 2794 | 3046 | if (getDerived().parseModuleNameOpt(Module)) |
| 2795 | 3047 | return nullptr; |
| 2796 | 3048 | |
| 3049 | bool IsMemberLikeFriend = Scope && consumeIf('F'); | |
| 3050 | ||
| 2797 | 3051 | consumeIf('L'); |
| 2798 | 3052 | |
| 2799 | 3053 | Node *Result; |
| ... | ... | @@ -2824,7 +3078,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName( |
| 2824 | 3078 | Result = make<ModuleEntity>(Module, Result); |
| 2825 | 3079 | if (Result != nullptr) |
| 2826 | 3080 | Result = getDerived().parseAbiTags(Result); |
| 2827 | if (Result != nullptr && Scope != nullptr) | |
| 3081 | if (Result != nullptr && IsMemberLikeFriend) | |
| 3082 | Result = make<MemberLikeFriendName>(Scope, Result); | |
| 3083 | else if (Result != nullptr && Scope != nullptr) | |
| 2828 | 3084 | Result = make<NestedName>(Scope, Result); |
| 2829 | 3085 | |
| 2830 | 3086 | return Result; |
| ... | ... | @@ -2856,7 +3112,8 @@ bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt( |
| 2856 | 3112 | // |
| 2857 | 3113 | // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ |
| 2858 | 3114 | // |
| 2859 | // <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters | |
| 3115 | // <lambda-sig> ::= <template-param-decl>* [Q <requires-clause expression>] | |
| 3116 | // <parameter type>+ # or "v" if the lambda has no parameters | |
| 2860 | 3117 | template <typename Derived, typename Alloc> |
| 2861 | 3118 | Node * |
| 2862 | 3119 | AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { |
| ... | ... | @@ -2877,10 +3134,10 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { |
| 2877 | 3134 | ScopedTemplateParamList LambdaTemplateParams(this); |
| 2878 | 3135 | |
| 2879 | 3136 | size_t ParamsBegin = Names.size(); |
| 2880 | while (look() == 'T' && | |
| 2881 | std::string_view("yptn").find(look(1)) != std::string_view::npos) { | |
| 2882 | Node *T = parseTemplateParamDecl(); | |
| 2883 | if (!T) | |
| 3137 | while (getDerived().isTemplateParamDecl()) { | |
| 3138 | Node *T = | |
| 3139 | getDerived().parseTemplateParamDecl(LambdaTemplateParams.params()); | |
| 3140 | if (T == nullptr) | |
| 2884 | 3141 | return nullptr; |
| 2885 | 3142 | Names.push_back(T); |
| 2886 | 3143 | } |
| ... | ... | @@ -2911,20 +3168,38 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { |
| 2911 | 3168 | if (TempParams.empty()) |
| 2912 | 3169 | TemplateParams.pop_back(); |
| 2913 | 3170 | |
| 2914 | if (!consumeIf("vE")) { | |
| 3171 | Node *Requires1 = nullptr; | |
| 3172 | if (consumeIf('Q')) { | |
| 3173 | Requires1 = getDerived().parseConstraintExpr(); | |
| 3174 | if (Requires1 == nullptr) | |
| 3175 | return nullptr; | |
| 3176 | } | |
| 3177 | ||
| 3178 | if (!consumeIf("v")) { | |
| 2915 | 3179 | do { |
| 2916 | 3180 | Node *P = getDerived().parseType(); |
| 2917 | 3181 | if (P == nullptr) |
| 2918 | 3182 | return nullptr; |
| 2919 | 3183 | Names.push_back(P); |
| 2920 | } while (!consumeIf('E')); | |
| 3184 | } while (look() != 'E' && look() != 'Q'); | |
| 2921 | 3185 | } |
| 2922 | 3186 | NodeArray Params = popTrailingNodeArray(ParamsBegin); |
| 2923 | 3187 | |
| 3188 | Node *Requires2 = nullptr; | |
| 3189 | if (consumeIf('Q')) { | |
| 3190 | Requires2 = getDerived().parseConstraintExpr(); | |
| 3191 | if (Requires2 == nullptr) | |
| 3192 | return nullptr; | |
| 3193 | } | |
| 3194 | ||
| 3195 | if (!consumeIf('E')) | |
| 3196 | return nullptr; | |
| 3197 | ||
| 2924 | 3198 | std::string_view Count = parseNumber(); |
| 2925 | 3199 | if (!consumeIf('_')) |
| 2926 | 3200 | return nullptr; |
| 2927 | return make<ClosureTypeName>(TempParams, Params, Count); | |
| 3201 | return make<ClosureTypeName>(TempParams, Requires1, Params, Requires2, | |
| 3202 | Count); | |
| 2928 | 3203 | } |
| 2929 | 3204 | if (consumeIf("Ub")) { |
| 2930 | 3205 | (void)parseNumber(); |
| ... | ... | @@ -3190,15 +3465,25 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) { |
| 3190 | 3465 | if (!consumeIf('N')) |
| 3191 | 3466 | return nullptr; |
| 3192 | 3467 | |
| 3193 | Qualifiers CVTmp = parseCVQualifiers(); | |
| 3194 | if (State) State->CVQualifiers = CVTmp; | |
| 3468 | // 'H' specifies that the encoding that follows | |
| 3469 | // has an explicit object parameter. | |
| 3470 | if (!consumeIf('H')) { | |
| 3471 | Qualifiers CVTmp = parseCVQualifiers(); | |
| 3472 | if (State) | |
| 3473 | State->CVQualifiers = CVTmp; | |
| 3195 | 3474 | |
| 3196 | if (consumeIf('O')) { | |
| 3197 | if (State) State->ReferenceQualifier = FrefQualRValue; | |
| 3198 | } else if (consumeIf('R')) { | |
| 3199 | if (State) State->ReferenceQualifier = FrefQualLValue; | |
| 3200 | } else { | |
| 3201 | if (State) State->ReferenceQualifier = FrefQualNone; | |
| 3475 | if (consumeIf('O')) { | |
| 3476 | if (State) | |
| 3477 | State->ReferenceQualifier = FrefQualRValue; | |
| 3478 | } else if (consumeIf('R')) { | |
| 3479 | if (State) | |
| 3480 | State->ReferenceQualifier = FrefQualLValue; | |
| 3481 | } else { | |
| 3482 | if (State) | |
| 3483 | State->ReferenceQualifier = FrefQualNone; | |
| 3484 | } | |
| 3485 | } else if (State) { | |
| 3486 | State->HasExplicitObjectParameter = true; | |
| 3202 | 3487 | } |
| 3203 | 3488 | |
| 3204 | 3489 | Node *SoFar = nullptr; |
| ... | ... | @@ -3446,7 +3731,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) { |
| 3446 | 3731 | } |
| 3447 | 3732 | } |
| 3448 | 3733 | |
| 3449 | assert(SoFar != nullptr); | |
| 3734 | DEMANGLE_ASSERT(SoFar != nullptr, ""); | |
| 3450 | 3735 | |
| 3451 | 3736 | Node *Base = getDerived().parseBaseUnresolvedName(); |
| 3452 | 3737 | if (Base == nullptr) |
| ... | ... | @@ -3894,7 +4179,15 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { |
| 3894 | 4179 | // Typically, <builtin-type>s are not considered substitution candidates, |
| 3895 | 4180 | // but the exception to that exception is vendor extended types (Itanium C++ |
| 3896 | 4181 | // ABI 5.9.1). |
| 3897 | Result = make<NameType>(Res); | |
| 4182 | if (consumeIf('I')) { | |
| 4183 | Node *BaseType = parseType(); | |
| 4184 | if (BaseType == nullptr) | |
| 4185 | return nullptr; | |
| 4186 | if (!consumeIf('E')) | |
| 4187 | return nullptr; | |
| 4188 | Result = make<TransformedType>(Res, BaseType); | |
| 4189 | } else | |
| 4190 | Result = make<NameType>(Res); | |
| 3898 | 4191 | break; |
| 3899 | 4192 | } |
| 3900 | 4193 | case 'D': |
| ... | ... | @@ -3961,6 +4254,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { |
| 3961 | 4254 | case 'c': |
| 3962 | 4255 | First += 2; |
| 3963 | 4256 | return make<NameType>("decltype(auto)"); |
| 4257 | // ::= Dk <type-constraint> # constrained auto | |
| 4258 | // ::= DK <type-constraint> # constrained decltype(auto) | |
| 4259 | case 'k': | |
| 4260 | case 'K': { | |
| 4261 | std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)"; | |
| 4262 | First += 2; | |
| 4263 | Node *Constraint = getDerived().parseName(); | |
| 4264 | if (!Constraint) | |
| 4265 | return nullptr; | |
| 4266 | return make<PostfixQualifiedType>(Constraint, Kind); | |
| 4267 | } | |
| 3964 | 4268 | // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) |
| 3965 | 4269 | case 'n': |
| 3966 | 4270 | First += 2; |
| ... | ... | @@ -4512,6 +4816,75 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() { |
| 4512 | 4816 | Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); |
| 4513 | 4817 | } |
| 4514 | 4818 | |
| 4819 | template <typename Derived, typename Alloc> | |
| 4820 | Node *AbstractManglingParser<Derived, Alloc>::parseConstraintExpr() { | |
| 4821 | // Within this expression, all enclosing template parameter lists are in | |
| 4822 | // scope. | |
| 4823 | ScopedOverride<bool> SaveInConstraintExpr(InConstraintExpr, true); | |
| 4824 | return getDerived().parseExpr(); | |
| 4825 | } | |
| 4826 | ||
| 4827 | template <typename Derived, typename Alloc> | |
| 4828 | Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() { | |
| 4829 | NodeArray Params; | |
| 4830 | if (consumeIf("rQ")) { | |
| 4831 | // <expression> ::= rQ <bare-function-type> _ <requirement>+ E | |
| 4832 | size_t ParamsBegin = Names.size(); | |
| 4833 | while (!consumeIf('_')) { | |
| 4834 | Node *Type = getDerived().parseType(); | |
| 4835 | if (Type == nullptr) | |
| 4836 | return nullptr; | |
| 4837 | Names.push_back(Type); | |
| 4838 | } | |
| 4839 | Params = popTrailingNodeArray(ParamsBegin); | |
| 4840 | } else if (!consumeIf("rq")) { | |
| 4841 | // <expression> ::= rq <requirement>+ E | |
| 4842 | return nullptr; | |
| 4843 | } | |
| 4844 | ||
| 4845 | size_t ReqsBegin = Names.size(); | |
| 4846 | do { | |
| 4847 | Node *Constraint = nullptr; | |
| 4848 | if (consumeIf('X')) { | |
| 4849 | // <requirement> ::= X <expression> [N] [R <type-constraint>] | |
| 4850 | Node *Expr = getDerived().parseExpr(); | |
| 4851 | if (Expr == nullptr) | |
| 4852 | return nullptr; | |
| 4853 | bool Noexcept = consumeIf('N'); | |
| 4854 | Node *TypeReq = nullptr; | |
| 4855 | if (consumeIf('R')) { | |
| 4856 | TypeReq = getDerived().parseName(); | |
| 4857 | if (TypeReq == nullptr) | |
| 4858 | return nullptr; | |
| 4859 | } | |
| 4860 | Constraint = make<ExprRequirement>(Expr, Noexcept, TypeReq); | |
| 4861 | } else if (consumeIf('T')) { | |
| 4862 | // <requirement> ::= T <type> | |
| 4863 | Node *Type = getDerived().parseType(); | |
| 4864 | if (Type == nullptr) | |
| 4865 | return nullptr; | |
| 4866 | Constraint = make<TypeRequirement>(Type); | |
| 4867 | } else if (consumeIf('Q')) { | |
| 4868 | // <requirement> ::= Q <constraint-expression> | |
| 4869 | // | |
| 4870 | // FIXME: We use <expression> instead of <constraint-expression>. Either | |
| 4871 | // the requires expression is already inside a constraint expression, in | |
| 4872 | // which case it makes no difference, or we're in a requires-expression | |
| 4873 | // that might be partially-substituted, where the language behavior is | |
| 4874 | // not yet settled and clang mangles after substitution. | |
| 4875 | Node *NestedReq = getDerived().parseExpr(); | |
| 4876 | if (NestedReq == nullptr) | |
| 4877 | return nullptr; | |
| 4878 | Constraint = make<NestedRequirement>(NestedReq); | |
| 4879 | } | |
| 4880 | if (Constraint == nullptr) | |
| 4881 | return nullptr; | |
| 4882 | Names.push_back(Constraint); | |
| 4883 | } while (!consumeIf('E')); | |
| 4884 | ||
| 4885 | return make<RequiresExpr>(Params, popTrailingNodeArray(ReqsBegin)); | |
| 4886 | } | |
| 4887 | ||
| 4515 | 4888 | // <expression> ::= <unary operator-name> <expression> |
| 4516 | 4889 | // ::= <binary operator-name> <expression> <expression> |
| 4517 | 4890 | // ::= <ternary operator-name> <expression> <expression> <expression> |
| ... | ... | @@ -4748,6 +5121,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { |
| 4748 | 5121 | return Ex; |
| 4749 | 5122 | return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary); |
| 4750 | 5123 | } |
| 5124 | if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q')) | |
| 5125 | return parseRequiresExpr(); | |
| 4751 | 5126 | if (consumeIf("so")) |
| 4752 | 5127 | return parseSubobjectExpr(); |
| 4753 | 5128 | if (consumeIf("sp")) { |
| ... | ... | @@ -5026,29 +5401,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { |
| 5026 | 5401 | } |
| 5027 | 5402 | |
| 5028 | 5403 | // <encoding> ::= <function name> <bare-function-type> |
| 5404 | // [`Q` <requires-clause expr>] | |
| 5029 | 5405 | // ::= <data name> |
| 5030 | 5406 | // ::= <special-name> |
| 5031 | 5407 | template <typename Derived, typename Alloc> |
| 5032 | Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { | |
| 5408 | Node *AbstractManglingParser<Derived, Alloc>::parseEncoding(bool ParseParams) { | |
| 5033 | 5409 | // The template parameters of an encoding are unrelated to those of the |
| 5034 | 5410 | // enclosing context. |
| 5035 | class SaveTemplateParams { | |
| 5036 | AbstractManglingParser *Parser; | |
| 5037 | decltype(TemplateParams) OldParams; | |
| 5038 | decltype(OuterTemplateParams) OldOuterParams; | |
| 5039 | ||
| 5040 | public: | |
| 5041 | SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { | |
| 5042 | OldParams = std::move(Parser->TemplateParams); | |
| 5043 | OldOuterParams = std::move(Parser->OuterTemplateParams); | |
| 5044 | Parser->TemplateParams.clear(); | |
| 5045 | Parser->OuterTemplateParams.clear(); | |
| 5046 | } | |
| 5047 | ~SaveTemplateParams() { | |
| 5048 | Parser->TemplateParams = std::move(OldParams); | |
| 5049 | Parser->OuterTemplateParams = std::move(OldOuterParams); | |
| 5050 | } | |
| 5051 | } SaveTemplateParams(this); | |
| 5411 | SaveTemplateParams SaveTemplateParamsScope(this); | |
| 5052 | 5412 | |
| 5053 | 5413 | if (look() == 'G' || look() == 'T') |
| 5054 | 5414 | return getDerived().parseSpecialName(); |
| ... | ... | @@ -5071,6 +5431,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { |
| 5071 | 5431 | if (IsEndOfEncoding()) |
| 5072 | 5432 | return Name; |
| 5073 | 5433 | |
| 5434 | // ParseParams may be false at the top level only, when called from parse(). | |
| 5435 | // For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be | |
| 5436 | // false when demangling 3fooILZ3BarEET_f but is always true when demangling | |
| 5437 | // 3Bar. | |
| 5438 | if (!ParseParams) { | |
| 5439 | while (consume()) | |
| 5440 | ; | |
| 5441 | return Name; | |
| 5442 | } | |
| 5443 | ||
| 5074 | 5444 | Node *Attrs = nullptr; |
| 5075 | 5445 | if (consumeIf("Ua9enable_ifI")) { |
| 5076 | 5446 | size_t BeforeArgs = Names.size(); |
| ... | ... | @@ -5092,22 +5462,35 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { |
| 5092 | 5462 | return nullptr; |
| 5093 | 5463 | } |
| 5094 | 5464 | |
| 5095 | if (consumeIf('v')) | |
| 5096 | return make<FunctionEncoding>(ReturnType, Name, NodeArray(), | |
| 5097 | Attrs, NameInfo.CVQualifiers, | |
| 5098 | NameInfo.ReferenceQualifier); | |
| 5465 | NodeArray Params; | |
| 5466 | if (!consumeIf('v')) { | |
| 5467 | size_t ParamsBegin = Names.size(); | |
| 5468 | do { | |
| 5469 | Node *Ty = getDerived().parseType(); | |
| 5470 | if (Ty == nullptr) | |
| 5471 | return nullptr; | |
| 5099 | 5472 | |
| 5100 | size_t ParamsBegin = Names.size(); | |
| 5101 | do { | |
| 5102 | Node *Ty = getDerived().parseType(); | |
| 5103 | if (Ty == nullptr) | |
| 5473 | const bool IsFirstParam = ParamsBegin == Names.size(); | |
| 5474 | if (NameInfo.HasExplicitObjectParameter && IsFirstParam) | |
| 5475 | Ty = make<ExplicitObjectParameter>(Ty); | |
| 5476 | ||
| 5477 | if (Ty == nullptr) | |
| 5478 | return nullptr; | |
| 5479 | ||
| 5480 | Names.push_back(Ty); | |
| 5481 | } while (!IsEndOfEncoding() && look() != 'Q'); | |
| 5482 | Params = popTrailingNodeArray(ParamsBegin); | |
| 5483 | } | |
| 5484 | ||
| 5485 | Node *Requires = nullptr; | |
| 5486 | if (consumeIf('Q')) { | |
| 5487 | Requires = getDerived().parseConstraintExpr(); | |
| 5488 | if (!Requires) | |
| 5104 | 5489 | return nullptr; |
| 5105 | Names.push_back(Ty); | |
| 5106 | } while (!IsEndOfEncoding()); | |
| 5490 | } | |
| 5107 | 5491 | |
| 5108 | return make<FunctionEncoding>(ReturnType, Name, | |
| 5109 | popTrailingNodeArray(ParamsBegin), | |
| 5110 | Attrs, NameInfo.CVQualifiers, | |
| 5492 | return make<FunctionEncoding>(ReturnType, Name, Params, Attrs, Requires, | |
| 5493 | NameInfo.CVQualifiers, | |
| 5111 | 5494 | NameInfo.ReferenceQualifier); |
| 5112 | 5495 | } |
| 5113 | 5496 | |
| ... | ... | @@ -5134,7 +5517,8 @@ template <> |
| 5134 | 5517 | struct FloatData<long double> |
| 5135 | 5518 | { |
| 5136 | 5519 | #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ |
| 5137 | defined(__wasm__) || defined(__riscv) || defined(__loongarch__) | |
| 5520 | defined(__wasm__) || defined(__riscv) || defined(__loongarch__) || \ | |
| 5521 | defined(__ve__) | |
| 5138 | 5522 | static const size_t mangled_size = 32; |
| 5139 | 5523 | #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) |
| 5140 | 5524 | static const size_t mangled_size = 16; |
| ... | ... | @@ -5268,6 +5652,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { |
| 5268 | 5652 | // ::= TL <level-1> _ <parameter-2 non-negative number> _ |
| 5269 | 5653 | template <typename Derived, typename Alloc> |
| 5270 | 5654 | Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { |
| 5655 | const char *Begin = First; | |
| 5271 | 5656 | if (!consumeIf('T')) |
| 5272 | 5657 | return nullptr; |
| 5273 | 5658 | |
| ... | ... | @@ -5289,6 +5674,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { |
| 5289 | 5674 | return nullptr; |
| 5290 | 5675 | } |
| 5291 | 5676 | |
| 5677 | // We don't track enclosing template parameter levels well enough to reliably | |
| 5678 | // substitute them all within a <constraint-expression>, so print the | |
| 5679 | // parameter numbering instead for now. | |
| 5680 | // TODO: Track all enclosing template parameters and substitute them here. | |
| 5681 | if (InConstraintExpr) { | |
| 5682 | return make<NameType>(std::string_view(Begin, First - 1 - Begin)); | |
| 5683 | } | |
| 5684 | ||
| 5292 | 5685 | // If we're in a context where this <template-param> refers to a |
| 5293 | 5686 | // <template-arg> further ahead in the mangled name (currently just conversion |
| 5294 | 5687 | // operator types), then we should only look it up in the right context. |
| ... | ... | @@ -5297,7 +5690,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { |
| 5297 | 5690 | Node *ForwardRef = make<ForwardTemplateReference>(Index); |
| 5298 | 5691 | if (!ForwardRef) |
| 5299 | 5692 | return nullptr; |
| 5300 | assert(ForwardRef->getKind() == Node::KForwardTemplateReference); | |
| 5693 | DEMANGLE_ASSERT(ForwardRef->getKind() == Node::KForwardTemplateReference, | |
| 5694 | ""); | |
| 5301 | 5695 | ForwardTemplateRefs.push_back( |
| 5302 | 5696 | static_cast<ForwardTemplateReference *>(ForwardRef)); |
| 5303 | 5697 | return ForwardRef; |
| ... | ... | @@ -5326,11 +5720,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() { |
| 5326 | 5720 | // ::= Tt <template-param-decl>* E # template parameter |
| 5327 | 5721 | // ::= Tp <template-param-decl> # parameter pack |
| 5328 | 5722 | template <typename Derived, typename Alloc> |
| 5329 | Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { | |
| 5723 | Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl( | |
| 5724 | TemplateParamList *Params) { | |
| 5330 | 5725 | auto InventTemplateParamName = [&](TemplateParamKind Kind) { |
| 5331 | 5726 | unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; |
| 5332 | 5727 | Node *N = make<SyntheticTemplateParamName>(Kind, Index); |
| 5333 | if (N) TemplateParams.back()->push_back(N); | |
| 5728 | if (N && Params) | |
| 5729 | Params->push_back(N); | |
| 5334 | 5730 | return N; |
| 5335 | 5731 | }; |
| 5336 | 5732 | |
| ... | ... | @@ -5341,6 +5737,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { |
| 5341 | 5737 | return make<TypeTemplateParamDecl>(Name); |
| 5342 | 5738 | } |
| 5343 | 5739 | |
| 5740 | if (consumeIf("Tk")) { | |
| 5741 | Node *Constraint = getDerived().parseName(); | |
| 5742 | if (!Constraint) | |
| 5743 | return nullptr; | |
| 5744 | Node *Name = InventTemplateParamName(TemplateParamKind::Type); | |
| 5745 | if (!Name) | |
| 5746 | return nullptr; | |
| 5747 | return make<ConstrainedTypeTemplateParamDecl>(Constraint, Name); | |
| 5748 | } | |
| 5749 | ||
| 5344 | 5750 | if (consumeIf("Tn")) { |
| 5345 | 5751 | Node *Name = InventTemplateParamName(TemplateParamKind::NonType); |
| 5346 | 5752 | if (!Name) |
| ... | ... | @@ -5357,18 +5763,25 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { |
| 5357 | 5763 | return nullptr; |
| 5358 | 5764 | size_t ParamsBegin = Names.size(); |
| 5359 | 5765 | ScopedTemplateParamList TemplateTemplateParamParams(this); |
| 5360 | while (!consumeIf("E")) { | |
| 5361 | Node *P = parseTemplateParamDecl(); | |
| 5766 | Node *Requires = nullptr; | |
| 5767 | while (!consumeIf('E')) { | |
| 5768 | Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params()); | |
| 5362 | 5769 | if (!P) |
| 5363 | 5770 | return nullptr; |
| 5364 | 5771 | Names.push_back(P); |
| 5772 | if (consumeIf('Q')) { | |
| 5773 | Requires = getDerived().parseConstraintExpr(); | |
| 5774 | if (Requires == nullptr || !consumeIf('E')) | |
| 5775 | return nullptr; | |
| 5776 | break; | |
| 5777 | } | |
| 5365 | 5778 | } |
| 5366 | NodeArray Params = popTrailingNodeArray(ParamsBegin); | |
| 5367 | return make<TemplateTemplateParamDecl>(Name, Params); | |
| 5779 | NodeArray InnerParams = popTrailingNodeArray(ParamsBegin); | |
| 5780 | return make<TemplateTemplateParamDecl>(Name, InnerParams, Requires); | |
| 5368 | 5781 | } |
| 5369 | 5782 | |
| 5370 | 5783 | if (consumeIf("Tp")) { |
| 5371 | Node *P = parseTemplateParamDecl(); | |
| 5784 | Node *P = parseTemplateParamDecl(Params); | |
| 5372 | 5785 | if (!P) |
| 5373 | 5786 | return nullptr; |
| 5374 | 5787 | return make<TemplateParamPackDecl>(P); |
| ... | ... | @@ -5382,6 +5795,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() { |
| 5382 | 5795 | // ::= <expr-primary> # simple expressions |
| 5383 | 5796 | // ::= J <template-arg>* E # argument pack |
| 5384 | 5797 | // ::= LZ <encoding> E # extension |
| 5798 | // ::= <template-param-decl> <template-arg> | |
| 5385 | 5799 | template <typename Derived, typename Alloc> |
| 5386 | 5800 | Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() { |
| 5387 | 5801 | switch (look()) { |
| ... | ... | @@ -5416,6 +5830,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() { |
| 5416 | 5830 | // ::= <expr-primary> # simple expressions |
| 5417 | 5831 | return getDerived().parseExprPrimary(); |
| 5418 | 5832 | } |
| 5833 | case 'T': { | |
| 5834 | // Either <template-param> or a <template-param-decl> <template-arg>. | |
| 5835 | if (!getDerived().isTemplateParamDecl()) | |
| 5836 | return getDerived().parseType(); | |
| 5837 | Node *Param = getDerived().parseTemplateParamDecl(nullptr); | |
| 5838 | if (!Param) | |
| 5839 | return nullptr; | |
| 5840 | Node *Arg = getDerived().parseTemplateArg(); | |
| 5841 | if (!Arg) | |
| 5842 | return nullptr; | |
| 5843 | return make<TemplateParamQualifiedArg>(Param, Arg); | |
| 5844 | } | |
| 5419 | 5845 | default: |
| 5420 | 5846 | return getDerived().parseType(); |
| 5421 | 5847 | } |
| ... | ... | @@ -5438,30 +5864,39 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { |
| 5438 | 5864 | } |
| 5439 | 5865 | |
| 5440 | 5866 | size_t ArgsBegin = Names.size(); |
| 5867 | Node *Requires = nullptr; | |
| 5441 | 5868 | while (!consumeIf('E')) { |
| 5442 | 5869 | if (TagTemplates) { |
| 5443 | auto OldParams = std::move(TemplateParams); | |
| 5444 | 5870 | Node *Arg = getDerived().parseTemplateArg(); |
| 5445 | TemplateParams = std::move(OldParams); | |
| 5446 | 5871 | if (Arg == nullptr) |
| 5447 | 5872 | return nullptr; |
| 5448 | 5873 | Names.push_back(Arg); |
| 5449 | 5874 | Node *TableEntry = Arg; |
| 5875 | if (Arg->getKind() == Node::KTemplateParamQualifiedArg) { | |
| 5876 | TableEntry = | |
| 5877 | static_cast<TemplateParamQualifiedArg *>(TableEntry)->getArg(); | |
| 5878 | } | |
| 5450 | 5879 | if (Arg->getKind() == Node::KTemplateArgumentPack) { |
| 5451 | 5880 | TableEntry = make<ParameterPack>( |
| 5452 | 5881 | static_cast<TemplateArgumentPack*>(TableEntry)->getElements()); |
| 5453 | 5882 | if (!TableEntry) |
| 5454 | 5883 | return nullptr; |
| 5455 | 5884 | } |
| 5456 | TemplateParams.back()->push_back(TableEntry); | |
| 5885 | OuterTemplateParams.push_back(TableEntry); | |
| 5457 | 5886 | } else { |
| 5458 | 5887 | Node *Arg = getDerived().parseTemplateArg(); |
| 5459 | 5888 | if (Arg == nullptr) |
| 5460 | 5889 | return nullptr; |
| 5461 | 5890 | Names.push_back(Arg); |
| 5462 | 5891 | } |
| 5892 | if (consumeIf('Q')) { | |
| 5893 | Requires = getDerived().parseConstraintExpr(); | |
| 5894 | if (!Requires || !consumeIf('E')) | |
| 5895 | return nullptr; | |
| 5896 | break; | |
| 5897 | } | |
| 5463 | 5898 | } |
| 5464 | return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin)); | |
| 5899 | return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin), Requires); | |
| 5465 | 5900 | } |
| 5466 | 5901 | |
| 5467 | 5902 | // <mangled-name> ::= _Z <encoding> |
| ... | ... | @@ -5470,9 +5905,9 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) { |
| 5470 | 5905 | // extension ::= ___Z <encoding> _block_invoke<decimal-digit>+ |
| 5471 | 5906 | // extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+ |
| 5472 | 5907 | template <typename Derived, typename Alloc> |
| 5473 | Node *AbstractManglingParser<Derived, Alloc>::parse() { | |
| 5908 | Node *AbstractManglingParser<Derived, Alloc>::parse(bool ParseParams) { | |
| 5474 | 5909 | if (consumeIf("_Z") || consumeIf("__Z")) { |
| 5475 | Node *Encoding = getDerived().parseEncoding(); | |
| 5910 | Node *Encoding = getDerived().parseEncoding(ParseParams); | |
| 5476 | 5911 | if (Encoding == nullptr) |
| 5477 | 5912 | return nullptr; |
| 5478 | 5913 | if (look() == '.') { |
| ... | ... | @@ -5486,7 +5921,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() { |
| 5486 | 5921 | } |
| 5487 | 5922 | |
| 5488 | 5923 | if (consumeIf("___Z") || consumeIf("____Z")) { |
| 5489 | Node *Encoding = getDerived().parseEncoding(); | |
| 5924 | Node *Encoding = getDerived().parseEncoding(ParseParams); | |
| 5490 | 5925 | if (Encoding == nullptr || !consumeIf("_block_invoke")) |
| 5491 | 5926 | return nullptr; |
| 5492 | 5927 | bool RequireNumber = consumeIf('_'); |
lib/libcxxabi/src/demangle/ItaniumNodes.def+9| ... | ... | @@ -19,6 +19,7 @@ NODE(QualType) |
| 19 | 19 | NODE(ConversionOperatorType) |
| 20 | 20 | NODE(PostfixQualifiedType) |
| 21 | 21 | NODE(ElaboratedTypeSpefType) |
| 22 | NODE(TransformedType) | |
| 22 | 23 | NODE(NameType) |
| 23 | 24 | NODE(AbiTagAttr) |
| 24 | 25 | NODE(EnableIfAttr) |
| ... | ... | @@ -36,6 +37,7 @@ NODE(SpecialName) |
| 36 | 37 | NODE(CtorVtableSpecialName) |
| 37 | 38 | NODE(QualifiedName) |
| 38 | 39 | NODE(NestedName) |
| 40 | NODE(MemberLikeFriendName) | |
| 39 | 41 | NODE(LocalName) |
| 40 | 42 | NODE(ModuleName) |
| 41 | 43 | NODE(ModuleEntity) |
| ... | ... | @@ -44,7 +46,9 @@ NODE(PixelVectorType) |
| 44 | 46 | NODE(BinaryFPType) |
| 45 | 47 | NODE(BitIntType) |
| 46 | 48 | NODE(SyntheticTemplateParamName) |
| 49 | NODE(TemplateParamQualifiedArg) | |
| 47 | 50 | NODE(TypeTemplateParamDecl) |
| 51 | NODE(ConstrainedTypeTemplateParamDecl) | |
| 48 | 52 | NODE(NonTypeTemplateParamDecl) |
| 49 | 53 | NODE(TemplateTemplateParamDecl) |
| 50 | 54 | NODE(TemplateParamPackDecl) |
| ... | ... | @@ -91,5 +95,10 @@ NODE(DoubleLiteral) |
| 91 | 95 | NODE(LongDoubleLiteral) |
| 92 | 96 | NODE(BracedExpr) |
| 93 | 97 | NODE(BracedRangeExpr) |
| 98 | NODE(RequiresExpr) | |
| 99 | NODE(ExprRequirement) | |
| 100 | NODE(TypeRequirement) | |
| 101 | NODE(NestedRequirement) | |
| 102 | NODE(ExplicitObjectParameter) | |
| 94 | 103 | |
| 95 | 104 | #undef NODE |
lib/libcxxabi/src/demangle/Utility.h+3-5| ... | ... | @@ -19,11 +19,9 @@ |
| 19 | 19 | #include "DemangleConfig.h" |
| 20 | 20 | |
| 21 | 21 | #include <array> |
| 22 | #include <cassert> | |
| 23 | 22 | #include <cstdint> |
| 24 | 23 | #include <cstdlib> |
| 25 | 24 | #include <cstring> |
| 26 | #include <exception> | |
| 27 | 25 | #include <limits> |
| 28 | 26 | #include <string_view> |
| 29 | 27 | |
| ... | ... | @@ -49,7 +47,7 @@ class OutputBuffer { |
| 49 | 47 | BufferCapacity = Need; |
| 50 | 48 | Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); |
| 51 | 49 | if (Buffer == nullptr) |
| 52 | std::terminate(); | |
| 50 | std::abort(); | |
| 53 | 51 | } |
| 54 | 52 | } |
| 55 | 53 | |
| ... | ... | @@ -160,7 +158,7 @@ public: |
| 160 | 158 | } |
| 161 | 159 | |
| 162 | 160 | void insert(size_t Pos, const char *S, size_t N) { |
| 163 | assert(Pos <= CurrentPosition); | |
| 161 | DEMANGLE_ASSERT(Pos <= CurrentPosition, ""); | |
| 164 | 162 | if (N == 0) |
| 165 | 163 | return; |
| 166 | 164 | grow(N); |
| ... | ... | @@ -173,7 +171,7 @@ public: |
| 173 | 171 | void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } |
| 174 | 172 | |
| 175 | 173 | char back() const { |
| 176 | assert(CurrentPosition); | |
| 174 | DEMANGLE_ASSERT(CurrentPosition, ""); | |
| 177 | 175 | return Buffer[CurrentPosition - 1]; |
| 178 | 176 | } |
| 179 | 177 |
lib/libcxxabi/src/fallback_malloc.cpp+5-4| ... | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | //===----------------------------------------------------------------------===// |
| 8 | 8 | |
| 9 | 9 | #include "fallback_malloc.h" |
| 10 | #include "abort_message.h" | |
| 10 | 11 | |
| 11 | 12 | #include <__threading_support> |
| 12 | 13 | #ifndef _LIBCXXABI_HAS_NO_THREADS |
| ... | ... | @@ -16,7 +17,7 @@ |
| 16 | 17 | #endif |
| 17 | 18 | |
| 18 | 19 | #include <__memory/aligned_alloc.h> |
| 19 | #include <assert.h> | |
| 20 | #include <__assert> | |
| 20 | 21 | #include <stdlib.h> // for malloc, calloc, free |
| 21 | 22 | #include <string.h> // for memset |
| 22 | 23 | |
| ... | ... | @@ -142,7 +143,7 @@ void* fallback_malloc(size_t len) { |
| 142 | 143 | |
| 143 | 144 | // Check the invariant that all heap_nodes pointers 'p' are aligned |
| 144 | 145 | // so that 'p + 1' has an alignment of at least RequiredAlignment |
| 145 | assert(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0); | |
| 146 | _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(p + 1) % RequiredAlignment == 0, ""); | |
| 146 | 147 | |
| 147 | 148 | // Calculate the number of extra padding elements needed in order |
| 148 | 149 | // to split 'p' and create a properly aligned heap_node from the tail |
| ... | ... | @@ -163,7 +164,7 @@ void* fallback_malloc(size_t len) { |
| 163 | 164 | q->next_node = 0; |
| 164 | 165 | q->len = static_cast<heap_size>(aligned_nelems); |
| 165 | 166 | void* ptr = q + 1; |
| 166 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | |
| 167 | _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, ""); | |
| 167 | 168 | return ptr; |
| 168 | 169 | } |
| 169 | 170 | |
| ... | ... | @@ -176,7 +177,7 @@ void* fallback_malloc(size_t len) { |
| 176 | 177 | prev->next_node = p->next_node; |
| 177 | 178 | p->next_node = 0; |
| 178 | 179 | void* ptr = p + 1; |
| 179 | assert(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0); | |
| 180 | _LIBCXXABI_ASSERT(reinterpret_cast<size_t>(ptr) % RequiredAlignment == 0, ""); | |
| 180 | 181 | return ptr; |
| 181 | 182 | } |
| 182 | 183 | } |
lib/libcxxabi/src/private_typeinfo.cpp+333-187| ... | ... | @@ -42,6 +42,7 @@ |
| 42 | 42 | // is_equal() with use_strcmp=false so the string names are not compared. |
| 43 | 43 | |
| 44 | 44 | #include <cstdint> |
| 45 | #include <cassert> | |
| 45 | 46 | #include <string.h> |
| 46 | 47 | |
| 47 | 48 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST |
| ... | ... | @@ -75,6 +76,242 @@ static inline ptrdiff_t update_offset_to_base(const char* vtable, |
| 75 | 76 | namespace __cxxabiv1 |
| 76 | 77 | { |
| 77 | 78 | |
| 79 | namespace { | |
| 80 | ||
| 81 | struct derived_object_info { | |
| 82 | const void* dynamic_ptr; | |
| 83 | const __class_type_info* dynamic_type; | |
| 84 | std::ptrdiff_t offset_to_derived; | |
| 85 | }; | |
| 86 | ||
| 87 | /// A helper function that gets (dynamic_ptr, dynamic_type, offset_to_derived) from static_ptr. | |
| 88 | void dyn_cast_get_derived_info(derived_object_info* info, const void* static_ptr) | |
| 89 | { | |
| 90 | #if __has_feature(cxx_abi_relative_vtable) | |
| 91 | // The vtable address will point to the first virtual function, which is 8 | |
| 92 | // bytes after the start of the vtable (4 for the offset from top + 4 for | |
| 93 | // the typeinfo component). | |
| 94 | const int32_t* vtable = | |
| 95 | *reinterpret_cast<const int32_t* const*>(static_ptr); | |
| 96 | info->offset_to_derived = static_cast<std::ptrdiff_t>(vtable[-2]); | |
| 97 | info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived; | |
| 98 | ||
| 99 | // The typeinfo component is now a relative offset to a proxy. | |
| 100 | int32_t offset_to_ti_proxy = vtable[-1]; | |
| 101 | const uint8_t* ptr_to_ti_proxy = | |
| 102 | reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy; | |
| 103 | info->dynamic_type = *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy)); | |
| 104 | #else | |
| 105 | void **vtable = *static_cast<void ** const *>(static_ptr); | |
| 106 | info->offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]); | |
| 107 | info->dynamic_ptr = static_cast<const char*>(static_ptr) + info->offset_to_derived; | |
| 108 | info->dynamic_type = static_cast<const __class_type_info*>(vtable[-1]); | |
| 109 | #endif | |
| 110 | } | |
| 111 | ||
| 112 | /// A helper function for __dynamic_cast that casts a base sub-object pointer | |
| 113 | /// to the object's dynamic type. | |
| 114 | /// | |
| 115 | /// This function returns the casting result directly. No further processing | |
| 116 | /// required. | |
| 117 | /// | |
| 118 | /// Specifically, this function can only be called if the following pre- | |
| 119 | /// condition holds: | |
| 120 | /// * The dynamic type of the object pointed to by `static_ptr` is exactly | |
| 121 | /// the same as `dst_type`. | |
| 122 | const void* dyn_cast_to_derived(const void* static_ptr, | |
| 123 | const void* dynamic_ptr, | |
| 124 | const __class_type_info* static_type, | |
| 125 | const __class_type_info* dst_type, | |
| 126 | std::ptrdiff_t offset_to_derived, | |
| 127 | std::ptrdiff_t src2dst_offset) | |
| 128 | { | |
| 129 | // We're downcasting from src_type to the complete object's dynamic type. | |
| 130 | // This is a really hot path that can be further optimized with the | |
| 131 | // `src2dst_offset` hint. | |
| 132 | // In such a case, dynamic_ptr already gives the casting result if the | |
| 133 | // casting ever succeeds. All we have to do now is to check static_ptr | |
| 134 | // points to a public base sub-object of dynamic_ptr. | |
| 135 | ||
| 136 | if (src2dst_offset >= 0) | |
| 137 | { | |
| 138 | // The static type is a unique public non-virtual base type of | |
| 139 | // dst_type at offset `src2dst_offset` from the origin of dst. | |
| 140 | // Note that there might be other non-public static_type bases. The | |
| 141 | // hint only guarantees that the public base is non-virtual and | |
| 142 | // unique. So we have to check whether static_ptr points to that | |
| 143 | // unique public base sub-object. | |
| 144 | if (offset_to_derived != -src2dst_offset) | |
| 145 | return nullptr; | |
| 146 | return dynamic_ptr; | |
| 147 | } | |
| 148 | ||
| 149 | if (src2dst_offset == -2) | |
| 150 | { | |
| 151 | // static_type is not a public base of dst_type. | |
| 152 | return nullptr; | |
| 153 | } | |
| 154 | ||
| 155 | // If src2dst_offset == -3, then: | |
| 156 | // src_type is a multiple public base type but never a virtual | |
| 157 | // base type. We can't conclude that static_ptr points to those | |
| 158 | // public base sub-objects because there might be other non- | |
| 159 | // public static_type bases. The search is inevitable. | |
| 160 | ||
| 161 | // Fallback to the slow path to check that static_type is a public | |
| 162 | // base type of dynamic_type. | |
| 163 | // Using giant short cut. Add that information to info. | |
| 164 | __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 165 | 1, // number_of_dst_type | |
| 166 | false, false, false, true, nullptr}; | |
| 167 | // Do the search | |
| 168 | dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); | |
| 169 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 170 | // The following if should always be false because we should | |
| 171 | // definitely find (static_ptr, static_type), either on a public | |
| 172 | // or private path | |
| 173 | if (info.path_dst_ptr_to_static_ptr == unknown) | |
| 174 | { | |
| 175 | // We get here only if there is some kind of visibility problem | |
| 176 | // in client code. | |
| 177 | static_assert(std::atomic<size_t>::is_always_lock_free, ""); | |
| 178 | static std::atomic<size_t> error_count(0); | |
| 179 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); | |
| 180 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) | |
| 181 | syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " | |
| 182 | "should have public visibility. At least one of them is hidden. %s" | |
| 183 | ", %s.\n", static_type->name(), dst_type->name()); | |
| 184 | // Redo the search comparing type_info's using strcmp | |
| 185 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, | |
| 186 | 0, 0, 0, false, false, false, true, nullptr}; | |
| 187 | info.number_of_dst_type = 1; | |
| 188 | dst_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); | |
| 189 | } | |
| 190 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 191 | // Query the search. | |
| 192 | if (info.path_dst_ptr_to_static_ptr != public_path) | |
| 193 | return nullptr; | |
| 194 | ||
| 195 | return dynamic_ptr; | |
| 196 | } | |
| 197 | ||
| 198 | /// A helper function for __dynamic_cast that tries to perform a downcast | |
| 199 | /// before giving up and falling back to the slow path. | |
| 200 | const void* dyn_cast_try_downcast(const void* static_ptr, | |
| 201 | const void* dynamic_ptr, | |
| 202 | const __class_type_info* dst_type, | |
| 203 | const __class_type_info* dynamic_type, | |
| 204 | std::ptrdiff_t src2dst_offset) | |
| 205 | { | |
| 206 | if (src2dst_offset < 0) | |
| 207 | { | |
| 208 | // We can only optimize the case if the static type is a unique public | |
| 209 | // base of dst_type. Give up. | |
| 210 | return nullptr; | |
| 211 | } | |
| 212 | ||
| 213 | // Pretend there is a dst_type object that leads to static_ptr. Later we | |
| 214 | // will check whether this imagined dst_type object exists. If it exists | |
| 215 | // then it will be the casting result. | |
| 216 | const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset; | |
| 217 | ||
| 218 | if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) < reinterpret_cast<std::intptr_t>(dynamic_ptr)) | |
| 219 | { | |
| 220 | // The imagined dst_type object does not exist. Bail-out quickly. | |
| 221 | return nullptr; | |
| 222 | } | |
| 223 | ||
| 224 | // Try to search a path from dynamic_type to dst_type. | |
| 225 | __dynamic_cast_info dynamic_to_dst_info = {dynamic_type, | |
| 226 | dst_ptr_to_static, | |
| 227 | dst_type, | |
| 228 | src2dst_offset, | |
| 229 | 0, | |
| 230 | 0, | |
| 231 | 0, | |
| 232 | 0, | |
| 233 | 0, | |
| 234 | 0, | |
| 235 | 0, | |
| 236 | 0, | |
| 237 | 1, // number_of_dst_type | |
| 238 | false, | |
| 239 | false, | |
| 240 | false, | |
| 241 | true, | |
| 242 | nullptr}; | |
| 243 | dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false); | |
| 244 | if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) { | |
| 245 | // We have found at least one path from dynamic_ptr to dst_ptr. The | |
| 246 | // downcast can succeed. | |
| 247 | return dst_ptr_to_static; | |
| 248 | } | |
| 249 | ||
| 250 | return nullptr; | |
| 251 | } | |
| 252 | ||
| 253 | const void* dyn_cast_slow(const void* static_ptr, | |
| 254 | const void* dynamic_ptr, | |
| 255 | const __class_type_info* static_type, | |
| 256 | const __class_type_info* dst_type, | |
| 257 | const __class_type_info* dynamic_type, | |
| 258 | std::ptrdiff_t src2dst_offset) | |
| 259 | { | |
| 260 | // Not using giant short cut. Do the search | |
| 261 | ||
| 262 | // Initialize info struct for this search. | |
| 263 | __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, | |
| 264 | 0, 0, 0, false, false, false, true, nullptr}; | |
| 265 | ||
| 266 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); | |
| 267 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 268 | // The following if should always be false because we should | |
| 269 | // definitely find (static_ptr, static_type), either on a public | |
| 270 | // or private path | |
| 271 | if (info.path_dst_ptr_to_static_ptr == unknown && | |
| 272 | info.path_dynamic_ptr_to_static_ptr == unknown) | |
| 273 | { | |
| 274 | static_assert(std::atomic<size_t>::is_always_lock_free, ""); | |
| 275 | static std::atomic<size_t> error_count(0); | |
| 276 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); | |
| 277 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) | |
| 278 | syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " | |
| 279 | "has hidden visibility or is defined in more than one translation " | |
| 280 | "unit. They should all have public visibility. " | |
| 281 | "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), | |
| 282 | dst_type->name()); | |
| 283 | // Redo the search comparing type_info's using strcmp | |
| 284 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, | |
| 285 | 0, 0, 0, false, false, false, true, nullptr}; | |
| 286 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); | |
| 287 | } | |
| 288 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 289 | // Query the search. | |
| 290 | switch (info.number_to_static_ptr) | |
| 291 | { | |
| 292 | case 0: | |
| 293 | if (info.number_to_dst_ptr == 1 && | |
| 294 | info.path_dynamic_ptr_to_static_ptr == public_path && | |
| 295 | info.path_dynamic_ptr_to_dst_ptr == public_path) | |
| 296 | return info.dst_ptr_not_leading_to_static_ptr; | |
| 297 | break; | |
| 298 | case 1: | |
| 299 | if (info.path_dst_ptr_to_static_ptr == public_path || | |
| 300 | ( | |
| 301 | info.number_to_dst_ptr == 0 && | |
| 302 | info.path_dynamic_ptr_to_static_ptr == public_path && | |
| 303 | info.path_dynamic_ptr_to_dst_ptr == public_path | |
| 304 | ) | |
| 305 | ) | |
| 306 | return info.dst_ptr_leading_to_static_ptr; | |
| 307 | break; | |
| 308 | } | |
| 309 | ||
| 310 | return nullptr; | |
| 311 | } | |
| 312 | ||
| 313 | } // namespace | |
| 314 | ||
| 78 | 315 | // __shim_type_info |
| 79 | 316 | |
| 80 | 317 | __shim_type_info::~__shim_type_info() |
| ... | ... | @@ -233,7 +470,8 @@ __class_type_info::can_catch(const __shim_type_info* thrown_type, |
| 233 | 470 | if (thrown_class_type == 0) |
| 234 | 471 | return false; |
| 235 | 472 | // bullet 2 |
| 236 | __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; | |
| 473 | assert(adjustedPtr && "catching a class without an object?"); | |
| 474 | __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, nullptr}; | |
| 237 | 475 | info.number_of_dst_type = 1; |
| 238 | 476 | thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); |
| 239 | 477 | 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, |
| 248 | 486 | #pragma clang diagnostic pop |
| 249 | 487 | #endif |
| 250 | 488 | |
| 489 | // When we have an object to inspect - we just pass the pointer to the sub- | |
| 490 | // object that matched the static_type we just checked. If that is different | |
| 491 | // from any previously recorded pointer to that object type, then we have | |
| 492 | // an ambiguous case. | |
| 493 | ||
| 494 | // When we have no object to inspect, we need to account for virtual bases | |
| 495 | // explicitly. | |
| 496 | // info->vbase_cookie is a pointer to the name of the innermost virtual base | |
| 497 | // type, or nullptr if there is no virtual base on the path so far. | |
| 498 | // adjustedPtr points to the subobject we just found. | |
| 499 | // If vbase_cookie != any previously recorded (including the case of nullptr | |
| 500 | // representing an already-found static sub-object) then we have an ambiguous | |
| 501 | // case. Assuming that the vbase_cookie values agree; if then we have a | |
| 502 | // different offset (adjustedPtr) from any previously recorded, this indicates | |
| 503 | // an ambiguous case within the virtual base. | |
| 504 | ||
| 251 | 505 | void |
| 252 | 506 | __class_type_info::process_found_base_class(__dynamic_cast_info* info, |
| 253 | 507 | void* adjustedPtr, |
| 254 | 508 | int path_below) const |
| 255 | 509 | { |
| 256 | if (info->dst_ptr_leading_to_static_ptr == 0) | |
| 257 | { | |
| 258 | // First time here | |
| 259 | info->dst_ptr_leading_to_static_ptr = adjustedPtr; | |
| 260 | info->path_dst_ptr_to_static_ptr = path_below; | |
| 261 | info->number_to_static_ptr = 1; | |
| 262 | } | |
| 263 | else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr) | |
| 264 | { | |
| 265 | // We've been here before. Update path to "most public" | |
| 266 | if (info->path_dst_ptr_to_static_ptr == not_public_path) | |
| 267 | info->path_dst_ptr_to_static_ptr = path_below; | |
| 268 | } | |
| 269 | else | |
| 270 | { | |
| 271 | // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) | |
| 272 | // to a static_type | |
| 273 | info->number_to_static_ptr += 1; | |
| 274 | info->path_dst_ptr_to_static_ptr = not_public_path; | |
| 275 | info->search_done = true; | |
| 276 | } | |
| 510 | if (info->number_to_static_ptr == 0) { | |
| 511 | // First time we found this base | |
| 512 | info->dst_ptr_leading_to_static_ptr = adjustedPtr; | |
| 513 | info->path_dst_ptr_to_static_ptr = path_below; | |
| 514 | // stash the virtual base cookie. | |
| 515 | info->dst_ptr_not_leading_to_static_ptr = info->vbase_cookie; | |
| 516 | info->number_to_static_ptr = 1; | |
| 517 | } else if (info->dst_ptr_not_leading_to_static_ptr == info->vbase_cookie && | |
| 518 | info->dst_ptr_leading_to_static_ptr == adjustedPtr) { | |
| 519 | // We've been here before. Update path to "most public" | |
| 520 | if (info->path_dst_ptr_to_static_ptr == not_public_path) | |
| 521 | info->path_dst_ptr_to_static_ptr = path_below; | |
| 522 | } else { | |
| 523 | // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) | |
| 524 | // to a static_type. | |
| 525 | info->number_to_static_ptr += 1; | |
| 526 | info->path_dst_ptr_to_static_ptr = not_public_path; | |
| 527 | info->search_done = true; | |
| 528 | } | |
| 277 | 529 | } |
| 278 | 530 | |
| 279 | 531 | void |
| ... | ... | @@ -301,16 +553,30 @@ __base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, |
| 301 | 553 | void* adjustedPtr, |
| 302 | 554 | int path_below) const |
| 303 | 555 | { |
| 304 | ptrdiff_t offset_to_base = 0; | |
| 305 | if (adjustedPtr != nullptr) | |
| 306 | { | |
| 307 | offset_to_base = __offset_flags >> __offset_shift; | |
| 308 | if (__offset_flags & __virtual_mask) | |
| 309 | { | |
| 310 | const char* vtable = *static_cast<const char*const*>(adjustedPtr); | |
| 311 | offset_to_base = update_offset_to_base(vtable, offset_to_base); | |
| 312 | } | |
| 556 | bool is_virtual = __offset_flags & __virtual_mask; | |
| 557 | ptrdiff_t offset_to_base = 0; | |
| 558 | if (info->have_object) { | |
| 559 | /* We have an object to inspect, we can look through its vtables to | |
| 560 | find the layout. */ | |
| 561 | offset_to_base = __offset_flags >> __offset_shift; | |
| 562 | if (is_virtual) { | |
| 563 | const char* vtable = *static_cast<const char* const*>(adjustedPtr); | |
| 564 | offset_to_base = update_offset_to_base(vtable, offset_to_base); | |
| 313 | 565 | } |
| 566 | } else if (!is_virtual) { | |
| 567 | /* We have no object; however, for non-virtual bases, (since we do not | |
| 568 | need to inspect any content) we can pretend to have an object based | |
| 569 | at '0'. */ | |
| 570 | offset_to_base = __offset_flags >> __offset_shift; | |
| 571 | } else { | |
| 572 | /* No object to inspect, and the next base is virtual. | |
| 573 | We cannot indirect through the vtable to find the actual object offset. | |
| 574 | So, update vbase_cookie to the new innermost virtual base using the | |
| 575 | pointer to the typeinfo name as a key. */ | |
| 576 | info->vbase_cookie = static_cast<const void*>(__base_type->name()); | |
| 577 | // .. and reset the pointer. | |
| 578 | adjustedPtr = nullptr; | |
| 579 | } | |
| 314 | 580 | __base_type->has_unambiguous_public_base( |
| 315 | 581 | info, |
| 316 | 582 | static_cast<char*>(adjustedPtr) + offset_to_base, |
| ... | ... | @@ -431,14 +697,22 @@ __pointer_type_info::can_catch(const __shim_type_info* thrown_type, |
| 431 | 697 | dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); |
| 432 | 698 | if (thrown_class_type == 0) |
| 433 | 699 | return false; |
| 434 | __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; | |
| 700 | bool have_object = adjustedPtr != nullptr; | |
| 701 | __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 702 | have_object, nullptr}; | |
| 435 | 703 | info.number_of_dst_type = 1; |
| 436 | 704 | thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); |
| 437 | 705 | if (info.path_dst_ptr_to_static_ptr == public_path) |
| 438 | 706 | { |
| 439 | if (adjustedPtr != NULL) | |
| 440 | adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); | |
| 441 | return true; | |
| 707 | // In the case of a thrown null pointer, we have no object but we might | |
| 708 | // well have computed the offset to where a public sub-object would be. | |
| 709 | // However, we do not want to return that offset to the user; we still | |
| 710 | // want them to catch a null ptr. | |
| 711 | if (have_object) | |
| 712 | adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); | |
| 713 | else | |
| 714 | adjustedPtr = nullptr; | |
| 715 | return true; | |
| 442 | 716 | } |
| 443 | 717 | return false; |
| 444 | 718 | } |
| ... | ... | @@ -623,174 +897,46 @@ extern "C" _LIBCXXABI_FUNC_VIS void * |
| 623 | 897 | __dynamic_cast(const void *static_ptr, const __class_type_info *static_type, |
| 624 | 898 | const __class_type_info *dst_type, |
| 625 | 899 | std::ptrdiff_t src2dst_offset) { |
| 626 | // Possible future optimization: Take advantage of src2dst_offset | |
| 627 | ||
| 628 | 900 | // Get (dynamic_ptr, dynamic_type) from static_ptr |
| 629 | #if __has_feature(cxx_abi_relative_vtable) | |
| 630 | // The vtable address will point to the first virtual function, which is 8 | |
| 631 | // bytes after the start of the vtable (4 for the offset from top + 4 for the typeinfo component). | |
| 632 | const int32_t* vtable = | |
| 633 | *reinterpret_cast<const int32_t* const*>(static_ptr); | |
| 634 | int32_t offset_to_derived = vtable[-2]; | |
| 635 | const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived; | |
| 636 | ||
| 637 | // The typeinfo component is now a relative offset to a proxy. | |
| 638 | int32_t offset_to_ti_proxy = vtable[-1]; | |
| 639 | const uint8_t* ptr_to_ti_proxy = | |
| 640 | reinterpret_cast<const uint8_t*>(vtable) + offset_to_ti_proxy; | |
| 641 | const __class_type_info* dynamic_type = | |
| 642 | *(reinterpret_cast<const __class_type_info* const*>(ptr_to_ti_proxy)); | |
| 643 | #else | |
| 644 | void **vtable = *static_cast<void ** const *>(static_ptr); | |
| 645 | ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]); | |
| 646 | const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived; | |
| 647 | const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]); | |
| 648 | #endif | |
| 901 | derived_object_info derived_info; | |
| 902 | dyn_cast_get_derived_info(&derived_info, static_ptr); | |
| 649 | 903 | |
| 650 | 904 | // Initialize answer to nullptr. This will be changed from the search |
| 651 | 905 | // results if a non-null answer is found. Regardless, this is what will |
| 652 | 906 | // be returned. |
| 653 | 907 | const void* dst_ptr = 0; |
| 654 | // Initialize info struct for this search. | |
| 655 | __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; | |
| 656 | 908 | |
| 657 | 909 | // Find out if we can use a giant short cut in the search |
| 658 | if (is_equal(dynamic_type, dst_type, false)) | |
| 910 | if (is_equal(derived_info.dynamic_type, dst_type, false)) | |
| 659 | 911 | { |
| 660 | // We're downcasting from src_type to the complete object's dynamic | |
| 661 | // type. This is a really hot path that can be further optimized | |
| 662 | // with the `src2dst_offset` hint. | |
| 663 | // In such a case, dynamic_ptr already gives the casting result if the | |
| 664 | // casting ever succeeds. All we have to do now is to check | |
| 665 | // static_ptr points to a public base sub-object of dynamic_ptr. | |
| 666 | ||
| 667 | if (src2dst_offset >= 0) | |
| 668 | { | |
| 669 | // The static type is a unique public non-virtual base type of | |
| 670 | // dst_type at offset `src2dst_offset` from the origin of dst. | |
| 671 | // Note that there might be other non-public static_type bases. The | |
| 672 | // hint only guarantees that the public base is non-virtual and | |
| 673 | // unique. So we have to check whether static_ptr points to that | |
| 674 | // unique public base sub-object. | |
| 675 | if (offset_to_derived == -src2dst_offset) | |
| 676 | dst_ptr = dynamic_ptr; | |
| 677 | } | |
| 678 | else if (src2dst_offset == -2) | |
| 679 | { | |
| 680 | // static_type is not a public base of dst_type. | |
| 681 | dst_ptr = nullptr; | |
| 682 | } | |
| 683 | else | |
| 684 | { | |
| 685 | // If src2dst_offset == -3, then: | |
| 686 | // src_type is a multiple public base type but never a virtual | |
| 687 | // base type. We can't conclude that static_ptr points to those | |
| 688 | // public base sub-objects because there might be other non- | |
| 689 | // public static_type bases. The search is inevitable. | |
| 690 | ||
| 691 | // Fallback to the slow path to check that static_type is a public | |
| 692 | // base type of dynamic_type. | |
| 693 | // Using giant short cut. Add that information to info. | |
| 694 | info.number_of_dst_type = 1; | |
| 695 | // Do the search | |
| 696 | dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, false); | |
| 697 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 698 | // The following if should always be false because we should | |
| 699 | // definitely find (static_ptr, static_type), either on a public | |
| 700 | // or private path | |
| 701 | if (info.path_dst_ptr_to_static_ptr == unknown) | |
| 702 | { | |
| 703 | // We get here only if there is some kind of visibility problem | |
| 704 | // in client code. | |
| 705 | static_assert(std::atomic<size_t>::is_always_lock_free, ""); | |
| 706 | static std::atomic<size_t> error_count(0); | |
| 707 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); | |
| 708 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) | |
| 709 | syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " | |
| 710 | "should have public visibility. At least one of them is hidden. %s" | |
| 711 | ", %s.\n", static_type->name(), dynamic_type->name()); | |
| 712 | // Redo the search comparing type_info's using strcmp | |
| 713 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | |
| 714 | info.number_of_dst_type = 1; | |
| 715 | dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path, true); | |
| 716 | } | |
| 717 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 718 | // Query the search. | |
| 719 | if (info.path_dst_ptr_to_static_ptr == public_path) | |
| 720 | dst_ptr = dynamic_ptr; | |
| 721 | } | |
| 912 | dst_ptr = dyn_cast_to_derived(static_ptr, | |
| 913 | derived_info.dynamic_ptr, | |
| 914 | static_type, | |
| 915 | dst_type, | |
| 916 | derived_info.offset_to_derived, | |
| 917 | src2dst_offset); | |
| 722 | 918 | } |
| 723 | 919 | else |
| 724 | 920 | { |
| 725 | if (src2dst_offset >= 0) | |
| 726 | { | |
| 727 | // Optimize toward downcasting: dst_type has one unique public | |
| 728 | // static_type bases. Let's first try to do a downcast before | |
| 729 | // falling back to the slow path. The downcast succeeds if there | |
| 730 | // is at least one path regardless of visibility from | |
| 731 | // dynamic_type to dst_type. | |
| 732 | const void* dst_ptr_to_static = reinterpret_cast<const char*>(static_ptr) - src2dst_offset; | |
| 733 | if (reinterpret_cast<std::intptr_t>(dst_ptr_to_static) >= reinterpret_cast<std::intptr_t>(dynamic_ptr)) | |
| 734 | { | |
| 735 | // Try to search a path from dynamic_type to dst_type. | |
| 736 | __dynamic_cast_info dynamic_to_dst_info = {dynamic_type, dst_ptr_to_static, dst_type, src2dst_offset}; | |
| 737 | dynamic_to_dst_info.number_of_dst_type = 1; | |
| 738 | dynamic_type->search_above_dst(&dynamic_to_dst_info, dynamic_ptr, dynamic_ptr, public_path, false); | |
| 739 | if (dynamic_to_dst_info.path_dst_ptr_to_static_ptr != unknown) { | |
| 740 | // We have found at least one path from dynamic_ptr to | |
| 741 | // dst_ptr. The downcast can succeed. | |
| 742 | dst_ptr = dst_ptr_to_static; | |
| 743 | } | |
| 744 | } | |
| 745 | } | |
| 921 | // Optimize toward downcasting: let's first try to do a downcast before | |
| 922 | // falling back to the slow path. | |
| 923 | dst_ptr = dyn_cast_try_downcast(static_ptr, | |
| 924 | derived_info.dynamic_ptr, | |
| 925 | dst_type, | |
| 926 | derived_info.dynamic_type, | |
| 927 | src2dst_offset); | |
| 746 | 928 | |
| 747 | 929 | if (!dst_ptr) |
| 748 | 930 | { |
| 749 | // Not using giant short cut. Do the search | |
| 750 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, false); | |
| 751 | #ifdef _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 752 | // The following if should always be false because we should | |
| 753 | // definitely find (static_ptr, static_type), either on a public | |
| 754 | // or private path | |
| 755 | if (info.path_dst_ptr_to_static_ptr == unknown && | |
| 756 | info.path_dynamic_ptr_to_static_ptr == unknown) | |
| 757 | { | |
| 758 | static_assert(std::atomic<size_t>::is_always_lock_free, ""); | |
| 759 | static std::atomic<size_t> error_count(0); | |
| 760 | size_t error_count_snapshot = error_count.fetch_add(1, std::memory_order_relaxed); | |
| 761 | if ((error_count_snapshot & (error_count_snapshot-1)) == 0) | |
| 762 | syslog(LOG_ERR, "dynamic_cast error 2: One or more of the following type_info's " | |
| 763 | "has hidden visibility or is defined in more than one translation " | |
| 764 | "unit. They should all have public visibility. " | |
| 765 | "%s, %s, %s.\n", static_type->name(), dynamic_type->name(), | |
| 766 | dst_type->name()); | |
| 767 | // Redo the search comparing type_info's using strcmp | |
| 768 | info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; | |
| 769 | dynamic_type->search_below_dst(&info, dynamic_ptr, public_path, true); | |
| 770 | } | |
| 771 | #endif // _LIBCXXABI_FORGIVING_DYNAMIC_CAST | |
| 772 | // Query the search. | |
| 773 | switch (info.number_to_static_ptr) | |
| 774 | { | |
| 775 | case 0: | |
| 776 | if (info.number_to_dst_ptr == 1 && | |
| 777 | info.path_dynamic_ptr_to_static_ptr == public_path && | |
| 778 | info.path_dynamic_ptr_to_dst_ptr == public_path) | |
| 779 | dst_ptr = info.dst_ptr_not_leading_to_static_ptr; | |
| 780 | break; | |
| 781 | case 1: | |
| 782 | if (info.path_dst_ptr_to_static_ptr == public_path || | |
| 783 | ( | |
| 784 | info.number_to_dst_ptr == 0 && | |
| 785 | info.path_dynamic_ptr_to_static_ptr == public_path && | |
| 786 | info.path_dynamic_ptr_to_dst_ptr == public_path | |
| 787 | ) | |
| 788 | ) | |
| 789 | dst_ptr = info.dst_ptr_leading_to_static_ptr; | |
| 790 | break; | |
| 791 | } | |
| 931 | dst_ptr = dyn_cast_slow(static_ptr, | |
| 932 | derived_info.dynamic_ptr, | |
| 933 | static_type, | |
| 934 | dst_type, | |
| 935 | derived_info.dynamic_type, | |
| 936 | src2dst_offset); | |
| 792 | 937 | } |
| 793 | 938 | } |
| 939 | ||
| 794 | 940 | return const_cast<void*>(dst_ptr); |
| 795 | 941 | } |
| 796 | 942 | |
| ... | ... | @@ -1075,7 +1221,7 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, |
| 1075 | 1221 | if (info->search_done) |
| 1076 | 1222 | break; |
| 1077 | 1223 | // If we just found a dst_type with a public path to (static_ptr, static_type), |
| 1078 | // then the only reason to continue the search is to make sure sure | |
| 1224 | // then the only reason to continue the search is to make sure | |
| 1079 | 1225 | // no other dst_type points to (static_ptr, static_type). |
| 1080 | 1226 | // If !diamond, then we don't need to search here. |
| 1081 | 1227 | // if we just found a dst_type with a private path to (static_ptr, static_type), |
lib/libcxxabi/src/private_typeinfo.h+7| ... | ... | @@ -110,6 +110,13 @@ struct _LIBCXXABI_HIDDEN __dynamic_cast_info |
| 110 | 110 | bool found_any_static_type; |
| 111 | 111 | // Set whenever a search can be stopped |
| 112 | 112 | bool search_done; |
| 113 | ||
| 114 | // Data that modifies the search mechanism. | |
| 115 | ||
| 116 | // There is no object (seen when we throw a null pointer to object). | |
| 117 | bool have_object; | |
| 118 | // Virtual base | |
| 119 | const void* vbase_cookie; | |
| 113 | 120 | }; |
| 114 | 121 | |
| 115 | 122 | // Has no base class |
lib/libcxxabi/src/stdlib_new_delete.cpp+190-212| ... | ... | @@ -7,7 +7,10 @@ |
| 7 | 7 | //===----------------------------------------------------------------------===// |
| 8 | 8 | |
| 9 | 9 | #include "__cxxabi_config.h" |
| 10 | #include "abort_message.h" | |
| 11 | #include "include/overridable_function.h" // from libc++ | |
| 10 | 12 | #include <__memory/aligned_alloc.h> |
| 13 | #include <cstddef> | |
| 11 | 14 | #include <cstdlib> |
| 12 | 15 | #include <new> |
| 13 | 16 | |
| ... | ... | @@ -25,241 +28,216 @@ |
| 25 | 28 | # error libc++ and libc++abi seem to disagree on whether exceptions are enabled |
| 26 | 29 | #endif |
| 27 | 30 | |
| 28 | // ------------------ BEGIN COPY ------------------ | |
| 29 | // Implement all new and delete operators as weak definitions | |
| 30 | // in this shared library, so that they can be overridden by programs | |
| 31 | // that define non-weak copies of the functions. | |
| 32 | ||
| 33 | _LIBCPP_WEAK | |
| 34 | void * | |
| 35 | operator new(std::size_t size) _THROW_BAD_ALLOC | |
| 36 | { | |
| 37 | if (size == 0) | |
| 38 | size = 1; | |
| 39 | void* p; | |
| 40 | while ((p = std::malloc(size)) == nullptr) | |
| 41 | { | |
| 42 | // If malloc fails and there is a new_handler, | |
| 43 | // call it to try free up memory. | |
| 44 | std::new_handler nh = std::get_new_handler(); | |
| 45 | if (nh) | |
| 46 | nh(); | |
| 47 | else | |
| 31 | inline void __throw_bad_alloc_shim() { | |
| 48 | 32 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS |
| 49 | throw std::bad_alloc(); | |
| 33 | throw std::bad_alloc(); | |
| 50 | 34 | #else |
| 51 | break; | |
| 35 | abort_message("bad_alloc was thrown in -fno-exceptions mode"); | |
| 52 | 36 | #endif |
| 53 | } | |
| 54 | return p; | |
| 55 | } | |
| 56 | ||
| 57 | _LIBCPP_WEAK | |
| 58 | void* | |
| 59 | operator new(size_t size, const std::nothrow_t&) noexcept | |
| 60 | { | |
| 61 | void* p = nullptr; | |
| 62 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 63 | try | |
| 64 | { | |
| 65 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 66 | p = ::operator new(size); | |
| 67 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 68 | } | |
| 69 | catch (...) | |
| 70 | { | |
| 71 | } | |
| 72 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 73 | return p; | |
| 74 | } | |
| 75 | ||
| 76 | _LIBCPP_WEAK | |
| 77 | void* | |
| 78 | operator new[](size_t size) _THROW_BAD_ALLOC | |
| 79 | { | |
| 80 | return ::operator new(size); | |
| 81 | 37 | } |
| 82 | 38 | |
| 83 | _LIBCPP_WEAK | |
| 84 | void* | |
| 85 | operator new[](size_t size, const std::nothrow_t&) noexcept | |
| 86 | { | |
| 87 | void* p = nullptr; | |
| 88 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 89 | try | |
| 90 | { | |
| 91 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 92 | p = ::operator new[](size); | |
| 93 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 94 | } | |
| 95 | catch (...) | |
| 96 | { | |
| 97 | } | |
| 98 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 99 | return p; | |
| 100 | } | |
| 39 | #define _LIBCPP_ASSERT_SHIM(expr, str) \ | |
| 40 | do { \ | |
| 41 | if (!expr) \ | |
| 42 | abort_message(str); \ | |
| 43 | } while (false) | |
| 101 | 44 | |
| 102 | _LIBCPP_WEAK | |
| 103 | void | |
| 104 | operator delete(void* ptr) noexcept | |
| 105 | { | |
| 106 | std::free(ptr); | |
| 107 | } | |
| 108 | ||
| 109 | _LIBCPP_WEAK | |
| 110 | void | |
| 111 | operator delete(void* ptr, const std::nothrow_t&) noexcept | |
| 112 | { | |
| 113 | ::operator delete(ptr); | |
| 114 | } | |
| 115 | ||
| 116 | _LIBCPP_WEAK | |
| 117 | void | |
| 118 | operator delete(void* ptr, size_t) noexcept | |
| 119 | { | |
| 120 | ::operator delete(ptr); | |
| 121 | } | |
| 122 | ||
| 123 | _LIBCPP_WEAK | |
| 124 | void | |
| 125 | operator delete[] (void* ptr) noexcept | |
| 126 | { | |
| 127 | ::operator delete(ptr); | |
| 128 | } | |
| 45 | // ------------------ BEGIN COPY ------------------ | |
| 46 | // Implement all new and delete operators as weak definitions | |
| 47 | // in this shared library, so that they can be overridden by programs | |
| 48 | // that define non-weak copies of the functions. | |
| 129 | 49 | |
| 130 | _LIBCPP_WEAK | |
| 131 | void | |
| 132 | operator delete[] (void* ptr, const std::nothrow_t&) noexcept | |
| 133 | { | |
| 134 | ::operator delete[](ptr); | |
| 50 | static void* operator_new_impl(std::size_t size) { | |
| 51 | if (size == 0) | |
| 52 | size = 1; | |
| 53 | void* p; | |
| 54 | while ((p = std::malloc(size)) == nullptr) { | |
| 55 | // If malloc fails and there is a new_handler, | |
| 56 | // call it to try free up memory. | |
| 57 | std::new_handler nh = std::get_new_handler(); | |
| 58 | if (nh) | |
| 59 | nh(); | |
| 60 | else | |
| 61 | break; | |
| 62 | } | |
| 63 | return p; | |
| 64 | } | |
| 65 | ||
| 66 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { | |
| 67 | void* p = operator_new_impl(size); | |
| 68 | if (p == nullptr) | |
| 69 | __throw_bad_alloc_shim(); | |
| 70 | return p; | |
| 71 | } | |
| 72 | ||
| 73 | _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { | |
| 74 | #ifdef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 75 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION | |
| 76 | _LIBCPP_ASSERT_SHIM( | |
| 77 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)), | |
| 78 | "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, " | |
| 79 | "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because " | |
| 80 | "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case " | |
| 81 | "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its " | |
| 82 | "contract (since it should return nullptr upon failure). Please make sure you override " | |
| 83 | "`operator new(size_t, nothrow_t)` as well."); | |
| 84 | # endif | |
| 85 | ||
| 86 | return operator_new_impl(size); | |
| 87 | #else | |
| 88 | void* p = nullptr; | |
| 89 | try { | |
| 90 | p = ::operator new(size); | |
| 91 | } catch (...) { | |
| 92 | } | |
| 93 | return p; | |
| 94 | #endif | |
| 135 | 95 | } |
| 136 | 96 | |
| 137 | _LIBCPP_WEAK | |
| 138 | void | |
| 139 | operator delete[] (void* ptr, size_t) noexcept | |
| 140 | { | |
| 141 | ::operator delete[](ptr); | |
| 97 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { | |
| 98 | return ::operator new(size); | |
| 142 | 99 | } |
| 143 | 100 | |
| 144 | #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) | |
| 101 | _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { | |
| 102 | #ifdef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 103 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION | |
| 104 | _LIBCPP_ASSERT_SHIM( | |
| 105 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])), | |
| 106 | "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " | |
| 107 | "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " | |
| 108 | "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " | |
| 109 | "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its " | |
| 110 | "contract (since it should return nullptr upon failure). Please make sure you override " | |
| 111 | "`operator new[](size_t, nothrow_t)` as well."); | |
| 112 | # endif | |
| 145 | 113 | |
| 146 | _LIBCPP_WEAK | |
| 147 | void * | |
| 148 | operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC | |
| 149 | { | |
| 150 | if (size == 0) | |
| 151 | size = 1; | |
| 152 | if (static_cast<size_t>(alignment) < sizeof(void*)) | |
| 153 | alignment = std::align_val_t(sizeof(void*)); | |
| 154 | ||
| 155 | // Try allocating memory. If allocation fails and there is a new_handler, | |
| 156 | // call it to try free up memory, and try again until it succeeds, or until | |
| 157 | // the new_handler decides to terminate. | |
| 158 | // | |
| 159 | // If allocation fails and there is no new_handler, we throw bad_alloc | |
| 160 | // (or return nullptr if exceptions are disabled). | |
| 161 | void* p; | |
| 162 | while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) | |
| 163 | { | |
| 164 | std::new_handler nh = std::get_new_handler(); | |
| 165 | if (nh) | |
| 166 | nh(); | |
| 167 | else { | |
| 168 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 169 | throw std::bad_alloc(); | |
| 114 | return operator_new_impl(size); | |
| 170 | 115 | #else |
| 171 | break; | |
| 116 | void* p = nullptr; | |
| 117 | try { | |
| 118 | p = ::operator new[](size); | |
| 119 | } catch (...) { | |
| 120 | } | |
| 121 | return p; | |
| 172 | 122 | #endif |
| 173 | } | |
| 174 | } | |
| 175 | return p; | |
| 176 | 123 | } |
| 177 | 124 | |
| 178 | _LIBCPP_WEAK | |
| 179 | void* | |
| 180 | operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept | |
| 181 | { | |
| 182 | void* p = nullptr; | |
| 183 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 184 | try | |
| 185 | { | |
| 186 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 187 | p = ::operator new(size, alignment); | |
| 188 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 189 | } | |
| 190 | catch (...) | |
| 191 | { | |
| 192 | } | |
| 193 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 194 | return p; | |
| 195 | } | |
| 125 | _LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } | |
| 196 | 126 | |
| 197 | _LIBCPP_WEAK | |
| 198 | void* | |
| 199 | operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC | |
| 200 | { | |
| 201 | return ::operator new(size, alignment); | |
| 202 | } | |
| 127 | _LIBCPP_WEAK void operator delete(void* ptr, const std::nothrow_t&) noexcept { ::operator delete(ptr); } | |
| 203 | 128 | |
| 204 | _LIBCPP_WEAK | |
| 205 | void* | |
| 206 | operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept | |
| 207 | { | |
| 208 | void* p = nullptr; | |
| 209 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 210 | try | |
| 211 | { | |
| 212 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 213 | p = ::operator new[](size, alignment); | |
| 214 | #ifndef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 215 | } | |
| 216 | catch (...) | |
| 217 | { | |
| 218 | } | |
| 219 | #endif // _LIBCPP_HAS_NO_EXCEPTIONS | |
| 220 | return p; | |
| 221 | } | |
| 222 | ||
| 223 | _LIBCPP_WEAK | |
| 224 | void | |
| 225 | operator delete(void* ptr, std::align_val_t) noexcept | |
| 226 | { | |
| 227 | std::__libcpp_aligned_free(ptr); | |
| 228 | } | |
| 129 | _LIBCPP_WEAK void operator delete(void* ptr, size_t) noexcept { ::operator delete(ptr); } | |
| 229 | 130 | |
| 230 | _LIBCPP_WEAK | |
| 231 | void | |
| 232 | operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept | |
| 233 | { | |
| 234 | ::operator delete(ptr, alignment); | |
| 235 | } | |
| 131 | _LIBCPP_WEAK void operator delete[](void* ptr) noexcept { ::operator delete(ptr); } | |
| 236 | 132 | |
| 237 | _LIBCPP_WEAK | |
| 238 | void | |
| 239 | operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept | |
| 240 | { | |
| 241 | ::operator delete(ptr, alignment); | |
| 242 | } | |
| 133 | _LIBCPP_WEAK void operator delete[](void* ptr, const std::nothrow_t&) noexcept { ::operator delete[](ptr); } | |
| 243 | 134 | |
| 244 | _LIBCPP_WEAK | |
| 245 | void | |
| 246 | operator delete[] (void* ptr, std::align_val_t alignment) noexcept | |
| 247 | { | |
| 248 | ::operator delete(ptr, alignment); | |
| 249 | } | |
| 135 | _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator delete[](ptr); } | |
| 250 | 136 | |
| 251 | _LIBCPP_WEAK | |
| 252 | void | |
| 253 | operator delete[] (void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept | |
| 254 | { | |
| 255 | ::operator delete[](ptr, alignment); | |
| 256 | } | |
| 137 | #if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) | |
| 257 | 138 | |
| 258 | _LIBCPP_WEAK | |
| 259 | void | |
| 260 | operator delete[] (void* ptr, size_t, std::align_val_t alignment) noexcept | |
| 261 | { | |
| 262 | ::operator delete[](ptr, alignment); | |
| 139 | static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { | |
| 140 | if (size == 0) | |
| 141 | size = 1; | |
| 142 | if (static_cast<size_t>(alignment) < sizeof(void*)) | |
| 143 | alignment = std::align_val_t(sizeof(void*)); | |
| 144 | ||
| 145 | // Try allocating memory. If allocation fails and there is a new_handler, | |
| 146 | // call it to try free up memory, and try again until it succeeds, or until | |
| 147 | // the new_handler decides to terminate. | |
| 148 | void* p; | |
| 149 | while ((p = std::__libcpp_aligned_alloc(static_cast<std::size_t>(alignment), size)) == nullptr) { | |
| 150 | std::new_handler nh = std::get_new_handler(); | |
| 151 | if (nh) | |
| 152 | nh(); | |
| 153 | else | |
| 154 | break; | |
| 155 | } | |
| 156 | return p; | |
| 157 | } | |
| 158 | ||
| 159 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* | |
| 160 | operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { | |
| 161 | void* p = operator_new_aligned_impl(size, alignment); | |
| 162 | if (p == nullptr) | |
| 163 | __throw_bad_alloc_shim(); | |
| 164 | return p; | |
| 165 | } | |
| 166 | ||
| 167 | _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { | |
| 168 | # ifdef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 169 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION | |
| 170 | _LIBCPP_ASSERT_SHIM( | |
| 171 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)), | |
| 172 | "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " | |
| 173 | "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " | |
| 174 | "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " | |
| 175 | "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` " | |
| 176 | "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override " | |
| 177 | "`operator new(size_t, align_val_t, nothrow_t)` as well."); | |
| 178 | # endif | |
| 179 | ||
| 180 | return operator_new_aligned_impl(size, alignment); | |
| 181 | # else | |
| 182 | void* p = nullptr; | |
| 183 | try { | |
| 184 | p = ::operator new(size, alignment); | |
| 185 | } catch (...) { | |
| 186 | } | |
| 187 | return p; | |
| 188 | # endif | |
| 189 | } | |
| 190 | ||
| 191 | _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* | |
| 192 | operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { | |
| 193 | return ::operator new(size, alignment); | |
| 194 | } | |
| 195 | ||
| 196 | _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { | |
| 197 | # ifdef _LIBCPP_HAS_NO_EXCEPTIONS | |
| 198 | # if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION | |
| 199 | _LIBCPP_ASSERT_SHIM( | |
| 200 | !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])), | |
| 201 | "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " | |
| 202 | "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " | |
| 203 | "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " | |
| 204 | "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, " | |
| 205 | "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you " | |
| 206 | "override " | |
| 207 | "`operator new[](size_t, align_val_t, nothrow_t)` as well."); | |
| 208 | # endif | |
| 209 | ||
| 210 | return operator_new_aligned_impl(size, alignment); | |
| 211 | # else | |
| 212 | void* p = nullptr; | |
| 213 | try { | |
| 214 | p = ::operator new[](size, alignment); | |
| 215 | } catch (...) { | |
| 216 | } | |
| 217 | return p; | |
| 218 | # endif | |
| 219 | } | |
| 220 | ||
| 221 | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } | |
| 222 | ||
| 223 | _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { | |
| 224 | ::operator delete(ptr, alignment); | |
| 225 | } | |
| 226 | ||
| 227 | _LIBCPP_WEAK void operator delete(void* ptr, size_t, std::align_val_t alignment) noexcept { | |
| 228 | ::operator delete(ptr, alignment); | |
| 229 | } | |
| 230 | ||
| 231 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment) noexcept { | |
| 232 | ::operator delete(ptr, alignment); | |
| 233 | } | |
| 234 | ||
| 235 | _LIBCPP_WEAK void operator delete[](void* ptr, std::align_val_t alignment, const std::nothrow_t&) noexcept { | |
| 236 | ::operator delete[](ptr, alignment); | |
| 237 | } | |
| 238 | ||
| 239 | _LIBCPP_WEAK void operator delete[](void* ptr, size_t, std::align_val_t alignment) noexcept { | |
| 240 | ::operator delete[](ptr, alignment); | |
| 263 | 241 | } |
| 264 | 242 | |
| 265 | 243 | #endif // !_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION |