STL/stl/inc/system_error

603 строки
23 KiB
C++
Исходник Обычный вид История

2019-09-05 01:57:56 +03:00
// system_error standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once
#ifndef _SYSTEM_ERROR_
#define _SYSTEM_ERROR_
#include <yvals.h>
2019-09-05 01:57:56 +03:00
#if _STL_COMPILER_PREPROCESSOR
#include <__msvc_system_error_abi.hpp>
2019-09-05 01:57:56 +03:00
#include <cerrno>
#include <cstdlib>
#include <stdexcept>
2019-09-05 01:57:56 +03:00
#include <xcall_once.h>
#include <xerrc.h>
#ifndef _M_CEE_PURE
#include <atomic>
#endif
2019-09-05 01:57:56 +03:00
#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
// ENUM CLASS io_errc
enum class io_errc { // error codes for ios_base::failure
stream = 1
};
// STRUCT TEMPLATE is_error_code_enum
template <class _Enum>
struct is_error_code_enum : false_type {};
template <>
struct is_error_code_enum<io_errc> : true_type {};
template <class _Ty>
_INLINE_VAR constexpr bool is_error_code_enum_v = is_error_code_enum<_Ty>::value;
// STRUCT TEMPLATE is_error_condition_enum
template <class _Enum>
struct is_error_condition_enum : false_type {};
template <>
struct is_error_condition_enum<errc> : true_type {};
template <class _Ty>
_INLINE_VAR constexpr bool is_error_condition_enum_v = is_error_condition_enum<_Ty>::value;
class error_code;
class error_condition;
_NODISCARD error_code make_error_code(errc) noexcept;
_NODISCARD error_code make_error_code(io_errc) noexcept;
_NODISCARD error_condition make_error_condition(errc) noexcept;
_NODISCARD error_condition make_error_condition(io_errc) noexcept;
// CLASS error_category
class error_category;
_NODISCARD const error_category& generic_category() noexcept;
_NODISCARD const error_category& iostream_category() noexcept;
_NODISCARD const error_category& system_category() noexcept;
class __declspec(novtable) error_category { // categorize an error
public:
/* constexpr */ error_category() noexcept { // TRANSITION, ABI
_Addr = reinterpret_cast<uintptr_t>(this);
}
#ifdef __cpp_constexpr_dynamic_alloc
constexpr
#endif
virtual ~error_category() noexcept = default;
2019-09-05 01:57:56 +03:00
_NODISCARD virtual const char* name() const noexcept = 0;
_NODISCARD virtual string message(int _Errval) const = 0;
_NODISCARD virtual error_condition default_error_condition(int _Errval) const noexcept;
_NODISCARD virtual bool equivalent(int _Errval, const error_condition& _Cond) const noexcept;
_NODISCARD virtual bool equivalent(const error_code& _Code, int _Errval) const noexcept;
_NODISCARD bool operator==(const error_category& _Right) const noexcept {
return _Addr == _Right._Addr;
}
_NODISCARD bool operator!=(const error_category& _Right) const noexcept {
return !(*this == _Right);
}
_NODISCARD bool operator<(const error_category& _Right) const noexcept {
return _Addr < _Right._Addr;
}
error_category(const error_category&) = delete;
error_category& operator=(const error_category&) = delete;
protected:
uintptr_t _Addr;
constexpr explicit error_category(const uintptr_t _Addr_) noexcept : _Addr(_Addr_) {}
enum : uintptr_t { // symbolic addresses for Standard error_category objects
2019-09-05 01:57:56 +03:00
_Future_addr = 1,
_Generic_addr = 3,
_Iostream_addr = 5,
_System_addr = 7
};
};
#if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
_NODISCARD inline bool _System_error_equal(const error_code&, const error_condition&) noexcept;
#endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
// CLASS error_code
class error_code { // store an implementation-specific error code and category
public:
error_code() noexcept : _Myval(0), _Mycat(&system_category()) { // construct non-error
}
error_code(int _Val, const error_category& _Cat) noexcept : _Myval(_Val), _Mycat(&_Cat) {}
template <class _Enum, enable_if_t<is_error_code_enum_v<_Enum>, int> = 0>
error_code(_Enum _Errcode) noexcept : _Myval(0), _Mycat(nullptr) {
*this = make_error_code(_Errcode); // using ADL
}
void assign(int _Val, const error_category& _Cat) noexcept {
_Myval = _Val;
_Mycat = &_Cat;
}
template <class _Enum, enable_if_t<is_error_code_enum_v<_Enum>, int> = 0>
error_code& operator=(_Enum _Errcode) noexcept {
*this = make_error_code(_Errcode); // using ADL
return *this;
}
void clear() noexcept {
_Myval = 0;
_Mycat = &system_category();
}
_NODISCARD int value() const noexcept {
return _Myval;
}
_NODISCARD const error_category& category() const noexcept {
return *_Mycat;
}
_NODISCARD error_condition default_error_condition() const noexcept;
_NODISCARD string message() const {
return category().message(value());
}
explicit operator bool() const noexcept {
return value() != 0;
}
#if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
_NODISCARD friend bool operator==(const error_code& _Left, const error_code& _Right) noexcept {
return _Left.category() == _Right.category() && _Left.value() == _Right.value();
}
_NODISCARD friend bool operator==(const error_code& _Left, const error_condition& _Right) noexcept {
return _System_error_equal(_Left, _Right);
}
_NODISCARD friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept {
return _System_error_equal(_Right, _Left);
}
_NODISCARD friend bool operator!=(const error_code& _Left, const error_code& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD friend bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept {
return !_System_error_equal(_Left, _Right);
}
_NODISCARD friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept {
return !_System_error_equal(_Right, _Left);
}
_NODISCARD friend bool operator<(const error_code& _Left, const error_code& _Right) noexcept {
return _Left.category() < _Right.category()
|| (_Left.category() == _Right.category() && _Left.value() < _Right.value());
}
#endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
private:
int _Myval; // the stored error number
const error_category* _Mycat; // pointer to error category
};
// CLASS error_condition
class error_condition { // store an abstract error code and category
public:
error_condition() noexcept : _Myval(0), _Mycat(&generic_category()) { // construct non-error
}
error_condition(int _Val, const error_category& _Cat) noexcept : _Myval(_Val), _Mycat(&_Cat) {}
template <class _Enum, enable_if_t<is_error_condition_enum_v<_Enum>, int> = 0>
error_condition(_Enum _Errcode) noexcept : _Myval(0), _Mycat(nullptr) {
*this = make_error_condition(_Errcode); // using ADL
}
void assign(int _Val, const error_category& _Cat) noexcept {
_Myval = _Val;
_Mycat = &_Cat;
}
template <class _Enum, enable_if_t<is_error_condition_enum_v<_Enum>, int> = 0>
error_condition& operator=(_Enum _Errcode) noexcept {
*this = make_error_condition(_Errcode); // using ADL
return *this;
}
void clear() noexcept {
_Myval = 0;
_Mycat = &generic_category();
}
_NODISCARD int value() const noexcept {
return _Myval;
}
_NODISCARD const error_category& category() const noexcept {
return *_Mycat;
}
_NODISCARD string message() const {
return category().message(value());
}
explicit operator bool() const noexcept {
return value() != 0;
}
#if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
_NODISCARD friend bool operator==(const error_condition& _Left, const error_condition& _Right) noexcept {
return _Left.category() == _Right.category() && _Left.value() == _Right.value();
}
_NODISCARD friend bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD friend bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept {
return _Left.category() < _Right.category()
|| (_Left.category() == _Right.category() && _Left.value() < _Right.value());
}
// We grant friendship to the operators from error_code here to allow is_error_code_enum_v but not
// is_error_condition_enum_v enums to be compared directly with error_condition; for example:
// io_errc::stream == make_error_condition(errc::out_of_memory)
friend bool operator==(const error_code& _Left, const error_condition& _Right) noexcept;
friend bool operator==(const error_condition& _Left, const error_code& _Right) noexcept;
friend bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept;
friend bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept;
#endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
private:
int _Myval; // the stored error number
const error_category* _Mycat; // pointer to error category
};
#if _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
_NODISCARD inline bool _System_error_equal(const error_code& _Left, const error_condition& _Right) noexcept {
return _Left.category().equivalent(_Left.value(), _Right) || _Right.category().equivalent(_Left, _Right.value());
}
#else // ^^^ _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS // !_STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS vvv
_NODISCARD inline bool operator==(const error_code& _Left, const error_code& _Right) noexcept {
return _Left.category() == _Right.category() && _Left.value() == _Right.value();
}
_NODISCARD inline bool operator==(const error_code& _Left, const error_condition& _Right) noexcept {
return _Left.category().equivalent(_Left.value(), _Right) || _Right.category().equivalent(_Left, _Right.value());
}
_NODISCARD inline bool operator==(const error_condition& _Left, const error_code& _Right) noexcept {
return _Right.category().equivalent(_Right.value(), _Left) || _Left.category().equivalent(_Right, _Left.value());
}
_NODISCARD inline bool operator==(const error_condition& _Left, const error_condition& _Right) noexcept {
return _Left.category() == _Right.category() && _Left.value() == _Right.value();
}
_NODISCARD inline bool operator!=(const error_code& _Left, const error_code& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD inline bool operator!=(const error_code& _Left, const error_condition& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD inline bool operator!=(const error_condition& _Left, const error_code& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD inline bool operator!=(const error_condition& _Left, const error_condition& _Right) noexcept {
return !(_Left == _Right);
}
_NODISCARD inline bool operator<(const error_code& _Left, const error_code& _Right) noexcept {
return _Left.category() < _Right.category()
|| (_Left.category() == _Right.category() && _Left.value() < _Right.value());
}
_NODISCARD inline bool operator<(const error_condition& _Left, const error_condition& _Right) noexcept {
return _Left.category() < _Right.category()
|| (_Left.category() == _Right.category() && _Left.value() < _Right.value());
}
#endif // _STL_OPTIMIZE_SYSTEM_ERROR_OPERATORS
// VIRTUALS FOR error_category
_NODISCARD inline error_condition error_category::default_error_condition(int _Errval) const noexcept {
// make error_condition for error code
2019-09-05 01:57:56 +03:00
return error_condition(_Errval, *this);
}
_NODISCARD inline bool error_category::equivalent(int _Errval, const error_condition& _Cond) const noexcept {
return default_error_condition(_Errval) == _Cond;
}
_NODISCARD inline bool error_category::equivalent(const error_code& _Code, int _Errval) const noexcept {
return *this == _Code.category() && _Code.value() == _Errval;
}
// MEMBER FUNCTIONS for error_code
_NODISCARD inline error_condition error_code::default_error_condition() const noexcept {
// make error_condition for error code
2019-09-05 01:57:56 +03:00
return category().default_error_condition(value());
}
// FUNCTION make_error_code
_NODISCARD inline error_code make_error_code(errc _Errno) noexcept {
return error_code(static_cast<int>(_Errno), generic_category());
}
_NODISCARD inline error_code make_error_code(io_errc _Errno) noexcept {
return error_code(static_cast<int>(_Errno), iostream_category());
}
// FUNCTION make_error_condition
_NODISCARD inline error_condition make_error_condition(errc _Errno) noexcept {
return error_condition(static_cast<int>(_Errno), generic_category());
}
_NODISCARD inline error_condition make_error_condition(io_errc _Errno) noexcept {
return error_condition(static_cast<int>(_Errno), iostream_category());
}
// STRUCT TEMPLATE SPECIALIZATION hash
template <>
struct hash<error_code> {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef error_code _ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME;
2019-09-05 01:57:56 +03:00
_NODISCARD size_t operator()(const error_code& _Keyval) const noexcept {
return hash<int>{}(_Keyval.value());
}
};
template <>
struct hash<error_condition> {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef error_condition _ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME;
2019-09-05 01:57:56 +03:00
_NODISCARD size_t operator()(const error_condition& _Keyval) const noexcept {
return hash<int>{}(_Keyval.value());
}
};
// CLASS system_error
class _System_error : public runtime_error { // base of all system-error exceptions
private:
static string _Makestr(error_code _Errcode, string _Message) { // compose error message
if (!_Message.empty()) {
_Message.append(": ");
}
_Message.append(_Errcode.message());
return _Message;
}
protected:
_System_error(error_code _Errcode, const string& _Message)
: runtime_error(_Makestr(_Errcode, _Message)), _Mycode(_Errcode) {}
error_code _Mycode; // the stored error code
};
class system_error : public _System_error { // base of all system-error exceptions
private:
using _Mybase = _System_error;
public:
system_error(error_code _Errcode) : _Mybase(_Errcode, "") {}
system_error(error_code _Errcode, const string& _Message) : _Mybase(_Errcode, _Message) {}
system_error(error_code _Errcode, const char* _Message) : _Mybase(_Errcode, _Message) {}
system_error(int _Errval, const error_category& _Errcat) : _Mybase(error_code(_Errval, _Errcat), "") {}
system_error(int _Errval, const error_category& _Errcat, const string& _Message)
: _Mybase(error_code(_Errval, _Errcat), _Message) {}
system_error(int _Errval, const error_category& _Errcat, const char* _Message)
: _Mybase(error_code(_Errval, _Errcat), _Message) {}
_NODISCARD const error_code& code() const noexcept {
return _Mycode;
}
#if !_HAS_EXCEPTIONS
2019-09-05 01:57:56 +03:00
protected:
virtual void _Doraise() const override { // perform class-specific exception handling
2019-09-05 01:57:56 +03:00
_RAISE(*this);
}
#endif // !_HAS_EXCEPTIONS
2019-09-05 01:57:56 +03:00
};
[[noreturn]] inline void _Throw_system_error(const errc _Errno) {
_THROW(system_error{_STD make_error_code(_Errno)});
}
_CRTIMP2_PURE const char* __CLRCALL_PURE_OR_CDECL _Syserror_map(int);
_CRTIMP2_PURE int __CLRCALL_PURE_OR_CDECL _Winerror_map(int);
struct _System_error_message {
char* _Str;
size_t _Length;
explicit _System_error_message(const unsigned long _Ec) noexcept
: _Str(nullptr), _Length(_CSTD __std_system_error_allocate_message(_Ec, &_Str)) {}
_System_error_message(const _System_error_message&) = delete;
_System_error_message& operator=(const _System_error_message&) = delete;
~_System_error_message() {
_CSTD __std_system_error_deallocate_message(_Str);
}
};
2019-09-05 01:57:56 +03:00
class _Generic_error_category : public error_category { // categorize a generic error
public:
constexpr _Generic_error_category() noexcept : error_category(_Generic_addr) {}
2019-09-05 01:57:56 +03:00
_NODISCARD virtual const char* name() const noexcept override {
return "generic";
}
_NODISCARD virtual string message(int _Errcode) const override {
return _Syserror_map(_Errcode);
}
};
class _Iostream_error_category2 : public error_category { // categorize an iostream error
2019-09-05 01:57:56 +03:00
public:
constexpr _Iostream_error_category2() noexcept : error_category(_Iostream_addr) {}
2019-09-05 01:57:56 +03:00
_NODISCARD virtual const char* name() const noexcept override {
return "iostream";
}
_NODISCARD virtual string message(int _Errcode) const override {
if (_Errcode == static_cast<int>(io_errc::stream)) {
static constexpr char _Iostream_error[] = "iostream stream error";
constexpr size_t _Iostream_error_length = sizeof(_Iostream_error) - 1; // TRANSITION, DevCom-906503
return string(_Iostream_error, _Iostream_error_length);
2019-09-05 01:57:56 +03:00
} else {
return _Syserror_map(_Errcode);
2019-09-05 01:57:56 +03:00
}
}
};
class _System_error_category : public error_category { // categorize an operating system error
public:
constexpr _System_error_category() noexcept : error_category(_System_addr) {}
2019-09-05 01:57:56 +03:00
_NODISCARD virtual const char* name() const noexcept override {
return "system";
}
_NODISCARD virtual string message(int _Errcode) const override {
const _System_error_message _Msg(static_cast<unsigned long>(_Errcode));
if (_Msg._Length == 0) {
static constexpr char _Unknown_error[] = "unknown error";
constexpr size_t _Unknown_error_length = sizeof(_Unknown_error) - 1; // TRANSITION, DevCom-906503
return string(_Unknown_error, _Unknown_error_length);
2019-09-05 01:57:56 +03:00
} else {
return string(_Msg._Str, _Msg._Length);
2019-09-05 01:57:56 +03:00
}
}
_NODISCARD virtual error_condition default_error_condition(int _Errval) const noexcept override {
// make error_condition for error code (generic if possible)
const int _Posv = _Winerror_map(_Errval);
if (_Posv == 0) {
return error_condition(_Errval, system_category());
} else {
return error_condition(_Posv, generic_category());
}
}
};
//
// TRANSITION, VSO-1043450
// _Immortalize_memcpy_image is used to provide a nonstandard guarantee.
// Specifically, we want the error category objects returned from things like std::system_category() to always
// be available, even during DLL unload (otherwise, <system_error> would be a huge regression vs. legacy error codes).
// Moreover, we need to be very conservative in the runtime support we request. Thus, we have these constraints:
//
// * can't use magic statics in standard modes, because that would inject a .TLS section into all binaries using
// <system_error> and would likely put borderline programs over the TLS slot count limit, and would destroy the
// variable during DLL unload
// * can't declare the error_category as an ordinary constexpr variable for most compilers, because error_category
// has a virtual destructor (TRANSITION, __cpp_constexpr_dynamic_alloc)
// * can't declare the error_category as an ordinary non-constexpr variable even with a constexpr constructor, because
// the compiler will emit code to destroy it which invalidates its use in these DLL shutdown scenarios
//
// As a result, we use a workaround: We create an atomic<uintptr_t> array to store the error_category instance, test
// if the first atomic is nonzero (acquire), and if so, we know we have formed the instance and can return a
// reinterpreted pointer to that storage. If the first atomic is zero, we write all except the first atomic (relaxed),
// then write the first one as a store-release. (The non-first values are transferred to other threads in the
// release sequence).
//
// Acknowledged undefined and implementation-defined behavior happening here:
// * There is a data race when filling in the values other than the first atomic; this is OK on all hardware we target
// because the racing threads are all writing identical values that never change afterwards.
// * We are reaching into the layout of atomic<uintptr_t>[N] and assuming we can reinterpret that as some other type.
// * We are assuming that virtual functions are implemented with a vfptr located as the first member of an object.
// (there are probably others)
//
// Inspecting the resulting assembly of any callers of _Immortalize_memcpy_image is recommended.
//
#if defined(_M_CEE_PURE)
// /clr:pure doesn't ever do constant initialization, so rely on the CLR and magic statics
template <class _Ty>
_NODISCARD const _Ty& _Immortalize_memcpy_image() noexcept {
/* MAGIC */ static _Immortalizer_impl<_Ty> _Static;
return _Static._Storage;
}
#elif defined(__cpp_constexpr_dynamic_alloc)
template <class _Ty>
_NODISCARD const _Ty& _Immortalize_memcpy_image() noexcept {
Allow Clang10 in the STL (#622) * Allow Clang10 in the STL This PR includes changes necessary to allow (but not require) clang 10 in the STL. It also includes test changes to allow the tests to pass given new clang warnings for deprecated behaviors, and an update to the LLVM reference to get similar changes that have been applied upstream to libc++ tests. Details: * In `<compare>`, remove workarounds for LLVM-41991 in Clang 10 RC1 fixed in RC2. * In `<concepts>`, remove `_SILENCE_CLANG_CONCEPTS_MESSAGE`. * In `<queue>` and `<stack>`, befriend only corresponding specializations of operator templates. * In `<system_error>`, fix the `__cpp_constexpr_dynamic_alloc` implementation of `_Immortalize_memcpy_image` (which we apparently didn't review at all). * In `<experimental/filesystem>`, apply a fix equivalent to the resolution of LWG-3244. * Update `P0220R1_optional` from upstream. * In `P0595R2_is_constant_evaluated`, silence Clang's warning for using `is_constant_evaluated` in a manifestly constant-evaluated context. * In `P0896R4_ranges_iterator_machinery`, fix bogus test cases that were expecting VSO-1008447, silence "unused variable" warnings, and avoid taking advantage of too-lenient MSVC comparison rewrite behavior. * In `P0896R4_ranges_range_machinery`, silence "unused variable" warning. * In `P0898R3_concepts`, Remove workaround for LLVM-44627 in Clang 10 RC1 fixed in RC2. * In `VSO_0000000_type_traits` and `tr1/type_traits5`, silence volatile function parameter deprecation warnings. * In `tr1/condition_variable`, `tr1/regex1`, and `tr1/regex3`, remove unnecessary copy assignment operators that were prompting Clang warnings about the implicitly definition of a copy constructor for such a class being deprecated. * In `tr1/csetjmp`, silence volatile increment deprecation warnings. Skip new libc++ tests: * Various `span` tests that expect `const_iterator` (libc++ doesn't yet implement LWG-3320) * tests for the implementation of P1135R6 "The C++ Synchronization Library" which we do not yet implement
2020-03-20 02:42:55 +03:00
static constexpr _Ty _Static;
return _Static;
}
#else // choose immortalize strategy
template <class _Ty>
_NODISCARD const _Ty& _Immortalize_memcpy_image() noexcept {
// return reference to a memcpy'd default-initialized _Ty
// pre: A default-initialized _Ty sets the first pointer-sized field to nonzero
constexpr size_t _Pointer_count = sizeof(_Ty) / sizeof(uintptr_t);
static atomic<uintptr_t> _Storage[_Pointer_count];
static_assert(sizeof(_Storage) == sizeof(_Ty), "Bad storage size");
static_assert(alignof(decltype(_Storage)) >= alignof(_Ty), "Bad alignment assumptions");
if (_Storage[0].load(memory_order_acquire) != 0) {
return reinterpret_cast<_Ty&>(_Storage);
}
const _Ty _Target;
const auto _Target_iter = reinterpret_cast<const uintptr_t*>(_STD addressof(_Target));
_CSTD memcpy(_Storage + 1, _Target_iter + 1, sizeof(_Ty) - sizeof(uintptr_t));
_Storage[0].store(_Target_iter[0], memory_order_release);
return reinterpret_cast<_Ty&>(_Storage);
}
#endif // choose immortalize strategy
2019-09-05 01:57:56 +03:00
_NODISCARD inline const error_category& generic_category() noexcept {
return _Immortalize_memcpy_image<_Generic_error_category>();
2019-09-05 01:57:56 +03:00
}
_NODISCARD inline const error_category& iostream_category() noexcept {
return _Immortalize_memcpy_image<_Iostream_error_category2>();
2019-09-05 01:57:56 +03:00
}
_NODISCARD inline const error_category& system_category() noexcept {
return _Immortalize_memcpy_image<_System_error_category>();
2019-09-05 01:57:56 +03:00
}
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _SYSTEM_ERROR_