[libcxx-commits] [libcxx] [libc++] Add MSVC's implementation of `exception_ptr` for Windows (PR #94977)

via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jun 10 06:21:18 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Stephan T. Lavavej (StephanTLavavej)

<details>
<summary>Changes</summary>

As requested by @<!-- -->petrhosek (and earlier by @<!-- -->llvm-beanz), Microsoft is happy to contribute our implementation of `exception_ptr` for Windows, under the Apache License v2.0 with LLVM Exception that our STLs share.

I've copied our files to plausible-looking places and updated their line endings and banners, but otherwise have made no attempt to integrate them into libc++. I copied all of our `<exception>` even though you only need `exception_ptr` from it. These are our current sources, corresponding to what's going to ship for production use in VS 2022 17.11.

Petr explained to me that libc++ developers will be able to do the integration work - please feel free to push arbitrary changes to my branch. I expect that significant overhauls will be necessary! (Significant improvements should be possible when you don't have to worry about the ancient evil `/clr:pure` etc.)

Please let me know if you need any more information or code. There's a bit of `shared_ptr` integration, where that machinery grants access to `_Exception_ptr_access` defined in `excptptr.cpp` - if you need the `<memory>` side of things, I can add that. (For the record, libc++ is always welcome to grab sources directly from microsoft/STL under our license, but we're also happy to deliver sources like this.)

The only caveat is that our "VCRuntime" support library is not open-source. If you need sources from VCRuntime, we'll have to figure out whether that's possible. Presumably this shouldn't be necessary, since our open-source microsoft/STL consumes the proprietary VCRuntime "at arm's length" and everything works.

Finally, although I've maintained our STL since 2007 and have worked on almost every part of it, I didn't write `exception_ptr` and its inner workings remain mysterious to me. It was written by a Microsoft dev who left the VC Libraries team in 2013 (and later, the company). If you have questions about what it's doing, I can try to get answers, but sometimes your guess will be as good as ours. :joy_cat: There's a potential performance improvement that could be made, which we're currently unable to do for ABI compatibility, see https://github.com/microsoft/STL/issues/751. I don't see any active bugs in our internal database about `exception_ptr`.

## Commits

* microsoft/STL's `excptptr.cpp`, copied verbatim.
  + From our `main` branch as of 2024-06-10: https://github.com/microsoft/STL/blob/e36ee6c2b9bc6f5b1f70776c18cf5d3a93a69798/stl/src/excptptr.cpp
* microsoft/STL's `<exception>`, copied verbatim as `win32_exception_ptr.h`.
  + From our `main` branch as of 2024-06-10: https://github.com/microsoft/STL/blob/e36ee6c2b9bc6f5b1f70776c18cf5d3a93a69798/stl/inc/exception
* Convert files to LF line endings.
* Add LLVM banners.
* Update `libcxx/CREDITS.TXT` to mention Microsoft.
  + I am intentionally not crediting myself here, I'm just delivering the pizza, I didn't cook it. :pizza:


---

Patch is 39.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94977.diff


3 Files Affected:

- (modified) libcxx/CREDITS.TXT (+1-1) 
- (added) libcxx/include/__exception/win32_exception_ptr.h (+430) 
- (added) libcxx/src/support/win32/excptptr.cpp (+541) 


``````````diff
diff --git a/libcxx/CREDITS.TXT b/libcxx/CREDITS.TXT
index aa3c8cf1a8c6e..6ed18072de9a5 100644
--- a/libcxx/CREDITS.TXT
+++ b/libcxx/CREDITS.TXT
@@ -98,7 +98,7 @@ E: lebrungrandt at ornl.gov
 D: Implementation of mdspan.
 
 N: Microsoft Corporation
-D: Contributed floating-point to_chars.
+D: Contributed floating-point to_chars and an implementation of exception_ptr for Windows.
 
 N: Bruce Mitchener, Jr.
 E: bruce.mitchener at gmail.com
diff --git a/libcxx/include/__exception/win32_exception_ptr.h b/libcxx/include/__exception/win32_exception_ptr.h
new file mode 100644
index 0000000000000..ec92762751822
--- /dev/null
+++ b/libcxx/include/__exception/win32_exception_ptr.h
@@ -0,0 +1,430 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// exception standard header
+
+// Copyright (c) Microsoft Corporation.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef _EXCEPTION_
+#define _EXCEPTION_
+#include <yvals.h>
+#if _STL_COMPILER_PREPROCESSOR
+
+#include <cstdlib>
+#include <type_traits>
+
+#pragma pack(push, _CRT_PACKING)
+#pragma warning(push, _STL_WARNING_LEVEL)
+#pragma warning(disable : _STL_DISABLED_WARNINGS)
+_STL_DISABLE_CLANG_WARNINGS
+#pragma push_macro("new")
+#undef new
+
+_STD_BEGIN
+
+#if _HAS_DEPRECATED_UNCAUGHT_EXCEPTION
+_EXPORT_STD extern "C++" _CXX17_DEPRECATE_UNCAUGHT_EXCEPTION _NODISCARD _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL
+    uncaught_exception() noexcept;
+#endif // _HAS_DEPRECATED_UNCAUGHT_EXCEPTION
+_EXPORT_STD extern "C++" _NODISCARD _CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL uncaught_exceptions() noexcept;
+
+_STD_END
+
+#if _HAS_EXCEPTIONS
+
+#include <malloc.h> // TRANSITION, VSO-2048380: This is unnecessary, but many projects assume it as of 2024-04-29
+#include <vcruntime_exception.h>
+
+_STD_BEGIN
+
+_EXPORT_STD using ::terminate;
+
+#ifndef _M_CEE_PURE
+_EXPORT_STD using ::set_terminate;
+_EXPORT_STD using ::terminate_handler;
+
+_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept {
+    // get current terminate handler
+    return _get_terminate();
+}
+#endif // !defined(_M_CEE_PURE)
+
+#if _HAS_UNEXPECTED
+using ::unexpected;
+
+#ifndef _M_CEE_PURE
+using ::set_unexpected;
+using ::unexpected_handler;
+
+_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept {
+    // get current unexpected handler
+    return _get_unexpected();
+}
+#endif // !defined(_M_CEE_PURE)
+#endif // _HAS_UNEXPECTED
+
+_STD_END
+
+#else // ^^^ _HAS_EXCEPTIONS / !_HAS_EXCEPTIONS vvv
+
+#pragma push_macro("stdext")
+#undef stdext
+
+_STDEXT_BEGIN
+class exception;
+_STDEXT_END
+
+_STD_BEGIN
+
+_EXPORT_STD using _STDEXT exception;
+
+using _Prhand = void(__cdecl*)(const exception&);
+
+extern _CRTIMP2_PURE_IMPORT _Prhand _Raise_handler; // pointer to raise handler
+
+_STD_END
+
+_STDEXT_BEGIN
+class exception { // base of all library exceptions
+public:
+    static _STD _Prhand _Set_raise_handler(_STD _Prhand _Pnew) { // register a handler for _Raise calls
+        const _STD _Prhand _Pold = _STD _Raise_handler;
+        _STD _Raise_handler      = _Pnew;
+        return _Pold;
+    }
+
+    // this constructor is necessary to compile
+    // successfully header new for _HAS_EXCEPTIONS==0 scenario
+    explicit __CLR_OR_THIS_CALL exception(const char* _Message = "unknown", int = 1) noexcept : _Ptr(_Message) {}
+
+    __CLR_OR_THIS_CALL exception(const exception& _Right) noexcept : _Ptr(_Right._Ptr) {}
+
+    exception& __CLR_OR_THIS_CALL operator=(const exception& _Right) noexcept {
+        _Ptr = _Right._Ptr;
+        return *this;
+    }
+
+    virtual __CLR_OR_THIS_CALL ~exception() noexcept {}
+
+    _NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept { // return pointer to message string
+        return _Ptr ? _Ptr : "unknown exception";
+    }
+
+    [[noreturn]] void __CLR_OR_THIS_CALL _Raise() const { // raise the exception
+        if (_STD _Raise_handler) {
+            (*_STD _Raise_handler)(*this); // call raise handler if present
+        }
+
+        _Doraise(); // call the protected virtual
+        _RAISE(*this); // raise this exception
+    }
+
+protected:
+    virtual void __CLR_OR_THIS_CALL _Doraise() const {} // perform class-specific exception handling
+
+    const char* _Ptr; // the message pointer
+};
+
+class bad_exception : public exception { // base of all bad exceptions
+public:
+    __CLR_OR_THIS_CALL bad_exception(const char* _Message = "bad exception") noexcept : exception(_Message) {}
+
+    __CLR_OR_THIS_CALL ~bad_exception() noexcept override {}
+
+protected:
+    void __CLR_OR_THIS_CALL _Doraise() const override { // raise this exception
+        _RAISE(*this);
+    }
+};
+
+class bad_array_new_length;
+
+class bad_alloc : public exception { // base of all bad allocation exceptions
+public:
+    __CLR_OR_THIS_CALL bad_alloc() noexcept
+        : exception("bad allocation", 1) {} // construct from message string with no memory allocation
+
+    __CLR_OR_THIS_CALL ~bad_alloc() noexcept override {}
+
+private:
+    friend bad_array_new_length;
+
+    __CLR_OR_THIS_CALL bad_alloc(const char* _Message) noexcept
+        : exception(_Message, 1) {} // construct from message string with no memory allocation
+
+protected:
+    void __CLR_OR_THIS_CALL _Doraise() const override { // perform class-specific exception handling
+        _RAISE(*this);
+    }
+};
+
+class bad_array_new_length : public bad_alloc {
+public:
+    bad_array_new_length() noexcept : bad_alloc("bad array new length") {}
+};
+
+_STDEXT_END
+
+_STD_BEGIN
+_EXPORT_STD using terminate_handler = void(__cdecl*)();
+
+_EXPORT_STD inline terminate_handler __CRTDECL set_terminate(terminate_handler) noexcept {
+    // register a terminate handler
+    return nullptr;
+}
+
+_EXPORT_STD [[noreturn]] inline void __CRTDECL terminate() noexcept {
+    // handle exception termination
+    _CSTD abort();
+}
+
+_EXPORT_STD _NODISCARD inline terminate_handler __CRTDECL get_terminate() noexcept {
+    // get current terminate handler
+    return nullptr;
+}
+
+#if _HAS_UNEXPECTED
+using unexpected_handler = void(__cdecl*)();
+
+inline unexpected_handler __CRTDECL set_unexpected(unexpected_handler) noexcept {
+    // register an unexpected handler
+    return nullptr;
+}
+
+inline void __CRTDECL unexpected() {} // handle unexpected exception
+
+_NODISCARD inline unexpected_handler __CRTDECL get_unexpected() noexcept {
+    // get current unexpected handler
+    return nullptr;
+}
+#endif // _HAS_UNEXPECTED
+
+_EXPORT_STD using _STDEXT bad_alloc;
+_EXPORT_STD using _STDEXT bad_array_new_length;
+_EXPORT_STD using _STDEXT bad_exception;
+
+_STD_END
+
+#pragma pop_macro("stdext")
+
+#endif // ^^^ !_HAS_EXCEPTIONS ^^^
+
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCreate(_Out_ void*) noexcept;
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrDestroy(_Inout_ void*) noexcept;
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopy(_Out_ void*, _In_ const void*) noexcept;
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrAssign(_Inout_ void*, _In_ const void*) noexcept;
+extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrCompare(
+    _In_ const void*, _In_ const void*) noexcept;
+extern "C++" _CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL __ExceptionPtrToBool(_In_ const void*) noexcept;
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrSwap(_Inout_ void*, _Inout_ void*) noexcept;
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCurrentException(void*) noexcept;
+extern "C++" [[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrRethrow(_In_ const void*);
+extern "C++" _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopyException(
+    _Inout_ void*, _In_ const void*, _In_ const void*) noexcept;
+
+_STD_BEGIN
+
+_EXPORT_STD class exception_ptr {
+public:
+    exception_ptr() noexcept {
+        __ExceptionPtrCreate(this);
+    }
+
+    exception_ptr(nullptr_t) noexcept {
+        __ExceptionPtrCreate(this);
+    }
+
+    ~exception_ptr() noexcept {
+        __ExceptionPtrDestroy(this);
+    }
+
+    exception_ptr(const exception_ptr& _Rhs) noexcept {
+        __ExceptionPtrCopy(this, &_Rhs);
+    }
+
+    exception_ptr& operator=(const exception_ptr& _Rhs) noexcept {
+        __ExceptionPtrAssign(this, &_Rhs);
+        return *this;
+    }
+
+    exception_ptr& operator=(nullptr_t) noexcept {
+        exception_ptr _Ptr;
+        __ExceptionPtrAssign(this, &_Ptr);
+        return *this;
+    }
+
+    explicit operator bool() const noexcept {
+        return __ExceptionPtrToBool(this);
+    }
+
+    static exception_ptr _Copy_exception(_In_ void* _Except, _In_ const void* _Ptr) {
+        exception_ptr _Retval;
+        if (!_Ptr) {
+            // unsupported exceptions
+            return _Retval;
+        }
+        __ExceptionPtrCopyException(&_Retval, _Except, _Ptr);
+        return _Retval;
+    }
+
+    friend void swap(exception_ptr& _Lhs, exception_ptr& _Rhs) noexcept {
+        __ExceptionPtrSwap(&_Lhs, &_Rhs);
+    }
+
+    _NODISCARD_FRIEND bool operator==(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept {
+        return __ExceptionPtrCompare(&_Lhs, &_Rhs);
+    }
+
+    _NODISCARD_FRIEND bool operator==(const exception_ptr& _Lhs, nullptr_t) noexcept {
+        return !_Lhs;
+    }
+
+#if !_HAS_CXX20
+    _NODISCARD_FRIEND bool operator==(nullptr_t, const exception_ptr& _Rhs) noexcept {
+        return !_Rhs;
+    }
+
+    _NODISCARD_FRIEND bool operator!=(const exception_ptr& _Lhs, const exception_ptr& _Rhs) noexcept {
+        return !(_Lhs == _Rhs);
+    }
+
+    _NODISCARD_FRIEND bool operator!=(const exception_ptr& _Lhs, nullptr_t) noexcept {
+        return !(_Lhs == nullptr);
+    }
+
+    _NODISCARD_FRIEND bool operator!=(nullptr_t, const exception_ptr& _Rhs) noexcept {
+        return !(nullptr == _Rhs);
+    }
+#endif // !_HAS_CXX20
+
+private:
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-private-field"
+#endif // defined(__clang__)
+    void* _Data1{};
+    void* _Data2{};
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // defined(__clang__)
+};
+
+_EXPORT_STD _NODISCARD inline exception_ptr current_exception() noexcept {
+    exception_ptr _Retval;
+    __ExceptionPtrCurrentException(&_Retval);
+    return _Retval;
+}
+
+_EXPORT_STD [[noreturn]] inline void rethrow_exception(_In_ exception_ptr _Ptr) {
+    __ExceptionPtrRethrow(&_Ptr);
+}
+
+template <class _Ex>
+void* __GetExceptionInfo(_Ex);
+
+_EXPORT_STD template <class _Ex>
+_NODISCARD_SMART_PTR_ALLOC exception_ptr make_exception_ptr(_Ex _Except) noexcept {
+    return exception_ptr::_Copy_exception(_STD addressof(_Except), __GetExceptionInfo(_Except));
+}
+
+_EXPORT_STD class nested_exception { // wrap an exception_ptr
+public:
+    nested_exception() noexcept : _Exc(_STD current_exception()) {}
+
+    nested_exception(const nested_exception&) noexcept            = default;
+    nested_exception& operator=(const nested_exception&) noexcept = default;
+    virtual ~nested_exception() noexcept {}
+
+    [[noreturn]] void rethrow_nested() const { // throw wrapped exception_ptr
+        if (_Exc) {
+            _STD rethrow_exception(_Exc);
+        } else {
+            _STD terminate(); // per N4950 [except.nested]/4
+        }
+    }
+
+    _NODISCARD exception_ptr nested_ptr() const noexcept { // return wrapped exception_ptr
+        return _Exc;
+    }
+
+private:
+    exception_ptr _Exc;
+};
+
+template <class _Uty>
+struct _With_nested_v2 : _Uty, nested_exception { // glue user exception to nested_exception
+    template <class _Ty>
+    explicit _With_nested_v2(_Ty&& _Arg)
+        : _Uty(_STD forward<_Ty>(_Arg)), nested_exception() {} // store user exception and current_exception()
+};
+
+_EXPORT_STD template <class _Ty>
+[[noreturn]] void throw_with_nested(_Ty&& _Arg) {
+    // throw user exception, glued to nested_exception if possible
+    using _Uty = decay_t<_Ty>;
+
+    if constexpr (is_class_v<_Uty> && !is_base_of_v<nested_exception, _Uty> && !is_final_v<_Uty>) {
+        // throw user exception glued to nested_exception
+        _THROW(_With_nested_v2<_Uty>(_STD forward<_Ty>(_Arg)));
+    } else {
+        // throw user exception by itself
+        _THROW(_STD forward<_Ty>(_Arg));
+    }
+}
+
+#ifdef _CPPRTTI
+_EXPORT_STD template <class _Ty>
+void rethrow_if_nested(const _Ty& _Arg) {
+    // detect nested_exception inheritance
+    constexpr bool _Can_use_dynamic_cast =
+        is_polymorphic_v<_Ty> && (!is_base_of_v<nested_exception, _Ty> || is_convertible_v<_Ty*, nested_exception*>);
+
+    if constexpr (_Can_use_dynamic_cast) {
+        const auto _Nested = dynamic_cast<const nested_exception*>(_STD addressof(_Arg));
+
+        if (_Nested) {
+            _Nested->rethrow_nested();
+        }
+    }
+}
+#else // ^^^ defined(_CPPRTTI) / !defined(_CPPRTTI) vvv
+_EXPORT_STD template <class _Ty>
+void rethrow_if_nested(const _Ty&) = delete; // requires /GR option
+#endif // ^^^ !defined(_CPPRTTI) ^^^
+
+_EXPORT_STD class bad_variant_access
+    : public exception { // exception for visit of a valueless variant or get<I> on a variant with index() != I
+public:
+    bad_variant_access() noexcept = default;
+
+    _NODISCARD const char* __CLR_OR_THIS_CALL what() const noexcept override {
+        return "bad variant access";
+    }
+
+#if !_HAS_EXCEPTIONS
+protected:
+    void _Doraise() const override { // perform class-specific exception handling
+        _RAISE(*this);
+    }
+#endif // ^^^ !_HAS_EXCEPTIONS ^^^
+};
+
+[[noreturn]] inline void _Throw_bad_variant_access() {
+    _THROW(bad_variant_access{});
+}
+
+_STD_END
+
+#pragma pop_macro("new")
+_STL_RESTORE_CLANG_WARNINGS
+#pragma warning(pop)
+#pragma pack(pop)
+
+#endif // _STL_COMPILER_PREPROCESSOR
+#endif // _EXCEPTION_
diff --git a/libcxx/src/support/win32/excptptr.cpp b/libcxx/src/support/win32/excptptr.cpp
new file mode 100644
index 0000000000000..a73c33cb1c7d7
--- /dev/null
+++ b/libcxx/src/support/win32/excptptr.cpp
@@ -0,0 +1,541 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Copyright (c) Microsoft Corporation.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// This implementation communicates with the EH runtime though vcruntime's per-thread-data structure; see
+// _pCurrentException in <trnsctrl.h>.
+//
+// As a result, normal EH runtime services (such as noexcept functions) are safe to use in this file.
+
+#ifndef _VCRT_ALLOW_INTERNALS
+#define _VCRT_ALLOW_INTERNALS
+#endif // !defined(_VCRT_ALLOW_INTERNALS)
+
+#include <Unknwn.h>
+#include <cstdlib> // for abort
+#include <cstring> // for memcpy
+#include <eh.h>
+#include <ehdata.h>
+#include <exception>
+#include <internal_shared.h>
+#include <malloc.h>
+#include <memory>
+#include <new>
+#include <stdexcept>
+#include <trnsctrl.h>
+#include <xcall_once.h>
+
+#include <Windows.h>
+
+// Pre-V4 managed exception code
+#define MANAGED_EXCEPTION_CODE 0XE0434F4D
+
+// V4 and later managed exception code
+#define MANAGED_EXCEPTION_CODE_V4 0XE0434352
+
+extern "C" _CRTIMP2 void* __cdecl __AdjustPointer(void*, const PMD&); // defined in frame.cpp
+
+using namespace std;
+
+namespace {
+#if defined(_M_CEE_PURE)
+    template <class _Ty>
+    _Ty& _Immortalize() { // return a reference to an object that will live forever
+        /* MAGIC */ static _Immortalizer_impl<_Ty> _Static;
+        return reinterpret_cast<_Ty&>(_Static._Storage);
+    }
+#elif !defined(_M_CEE)
+    template <class _Ty>
+    struct _Constexpr_excptptr_immortalize_impl {
+        union {
+            _Ty _Storage;
+        };
+
+        constexpr _Constexpr_excptptr_immortalize_impl() noexcept : _Storage{} {}
+
+        _Constexpr_excptptr_immortalize_impl(const _Constexpr_excptptr_immortalize_impl&)            = delete;
+        _Constexpr_excptptr_immortalize_impl& operator=(const _Constexpr_excptptr_immortalize_impl&) = delete;
+
+        _MSVC_NOOP_DTOR ~_Constexpr_excptptr_immortalize_impl() {
+            // do nothing, allowing _Ty to be used during shutdown
+        }
+    };
+
+    template <class _Ty>
+    _Constexpr_excptptr_immortalize_impl<_Ty> _Immortalize_impl;
+
+    template <class _Ty>
+    [[nodiscard]] _Ty& _Immortalize() noexcept {
+        return _Immortalize_impl<_Ty>._Storage;
+    }
+#else // ^^^ !defined(_M_CEE) / defined(_M_CEE), TRANSITION, VSO-1153256 vvv
+    template <class _Ty>
+    _Ty& _Immortalize() { // return a reference to an object that will live forever
+        static once_flag _Flag;
+        alignas(_Ty) static unsigned char _Storage[sizeof(_Ty)];
+        call_once(_Flag, [&_Storage] { ::new (static_cast<void*>(&_Storage)) _Ty(); });
+        return reinterpret_cast<_Ty&>(_Storage);
+    }
+#endif // ^^^ !defined(_M_CEE_PURE) && defined(_M_CEE), TRANSITION, VSO-1153256 ^^^
+
+    void _PopulateCppExceptionRecord(
+        _EXCEPTION_RECORD& _Record, const void* const _PExcept, ThrowInfo* _PThrow) noexcept {
+        _Record.ExceptionCode           = EH_EXCEPTION_NUMBER;
+        _Record.ExceptionFlags          = EXCEPTION_NONCONTINUABLE;
+        _Record.ExceptionRecord         = nullptr; // no SEH to chain
+        _Record.ExceptionAddress        = nullptr; // Address of exception. Will be overwritten by OS
+        _Record.NumberParameters        = EH_EXCEPTION_PARAMETERS;
+        _Record.ExceptionInformation[0] = EH_MAGIC_NUMBER1; // params.magicNumber
+        _Record.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(_PExcept); // params.pExceptionObject
+
+        if (_PThrow && (_PThrow->attributes & TI_IsWinRT)) {
+            // The pointer to the ExceptionInfo structure is stored sizeof(void*) in front of each WinRT Exception Info.
+            const auto _PWei = (*static_cast<WINRTEXCEPTIONINFO** const*>(_PExcept))[-1];
+            _PThrow          = _PWei->throwInfo;
+        }
+
+        _Record.ExceptionInformation[2] = reinterpret_cast<ULONG_PTR>(_PThrow); // params.pThrowInfo
+
+#if _EH_RELATIVE_TYPEINFO
+        void* _ThrowImageBase =
+            _PThrow ? RtlPcToFileHeader(const_cast<void*>(static_cast<const void*>(_PThrow)), &_ThrowImageBase)
+                    : nullptr;
+        _Record.ExceptionInformation[3] = reinterpret_cast<ULONG_PTR>(_ThrowImageBase); // params.pThrowImageBase
+#endif // _EH_RELATIVE_TYPEINFO
+
+        // If the throw info indicates this throw is from a pure region,
+        // set the magic number to the Pure one, so only a pure-region
+        // catch will see it.
+        //
+        // Also use the Pure magic number on 64-bit platforms if we were unable to
+        // determine an image base, since that was the old way to determine
+        // a pure throw, before the TI_IsPure bit was added to the FuncInfo
+        // attributes field.
+        if (_PThrow
+            && ((_PThrow->attributes & TI_IsPure)
+#if _EH_RELATIVE_TYPEINFO
+                || !_ThrowImageBase
+#endif // _EH_RELATIVE_TYPEINFO
+                )) {
+            _Record.ExceptionInformation[0] = EH_PURE_MAGIC_NUMBER1;
+        }
+    }
+
+    void _CopyExceptionRecord(_EXCEPTION_RECORD& _Dest, const _EXCEPTION_RECORD& _Src) noexcept {
+        _Dest.ExceptionCode = _Src.ExceptionCode;
+        // we force EXCEPTION_NONCONTINUABLE because rethrow_exception is [[noreturn]]
+        _Dest.ExceptionFlags   = _Src.ExceptionFlags | EXCEPTION_NONCONTINUABLE;
+        _Dest.ExceptionRecord  = nullptr; // We don't chain SEH exceptions
+        _Dest.ExceptionAddress = nullptr; // Useless field to copy. It will be overwritten by RaiseException()
+        const auto _Parameters = _Src.NumberParameters;
+        _Dest.NumberParameters = _Parameters;
+
+        // copy the numb...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/94977


More information about the libcxx-commits mailing list