diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -12,6 +12,7 @@ chrono.cpp condition_variable.cpp condition_variable_destructor.cpp + error_category.cpp exception.cpp functional.cpp future.cpp diff --git a/libcxx/src/error_category.cpp b/libcxx/src/error_category.cpp new file mode 100644 --- /dev/null +++ b/libcxx/src/error_category.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include <__config> + +#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS +# define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS +#endif + +#include + +_LIBCPP_BEGIN_NAMESPACE_STD + +// class error_category + +#if defined(_LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS) +error_category::error_category() noexcept +{ +} +#endif + +error_category::~error_category() noexcept +{ +} + +error_condition +error_category::default_error_condition(int ev) const noexcept +{ + return error_condition(ev, *this); +} + +bool +error_category::equivalent(int code, const error_condition& condition) const noexcept +{ + return default_error_condition(code) == condition; +} + +bool +error_category::equivalent(const error_code& code, int condition) const noexcept +{ + return *this == code.category() && code.value() == condition; +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/future.cpp b/libcxx/src/future.cpp --- a/libcxx/src/future.cpp +++ b/libcxx/src/future.cpp @@ -59,8 +59,15 @@ const error_category& future_category() noexcept { - static __future_error_category __f; - return __f; + union FutureErrorHelper { + __future_error_category future_error_category; + constexpr explicit FutureErrorHelper() + : future_error_category() {} + ~FutureErrorHelper() {} + }; + _LIBCPP_NO_DESTROY constinit + static FutureErrorHelper __f; + return __f.future_error_category; } future_error::future_error(error_code __ec) diff --git a/libcxx/src/ios.cpp b/libcxx/src/ios.cpp --- a/libcxx/src/ios.cpp +++ b/libcxx/src/ios.cpp @@ -52,8 +52,15 @@ const error_category& iostream_category() noexcept { - static __iostream_category s; - return s; + union IostreamErrorHelper { + __iostream_category iostream_error_category; + constexpr explicit IostreamErrorHelper() + : iostream_error_category() {} + ~IostreamErrorHelper() {} + }; + _LIBCPP_NO_DESTROY constinit + static IostreamErrorHelper s; + return s.iostream_error_category; } // ios_base::failure diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp --- a/libcxx/src/system_error.cpp +++ b/libcxx/src/system_error.cpp @@ -6,12 +6,8 @@ // //===----------------------------------------------------------------------===// -#include <__config> -#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS -# define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS -#endif - #include <__assert> +#include <__config> #include #include #include @@ -28,36 +24,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD -// class error_category - -#if defined(_LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS) -error_category::error_category() noexcept -{ -} -#endif - -error_category::~error_category() noexcept -{ -} - -error_condition -error_category::default_error_condition(int ev) const noexcept -{ - return error_condition(ev, *this); -} - -bool -error_category::equivalent(int code, const error_condition& condition) const noexcept -{ - return default_error_condition(code) == condition; -} - -bool -error_category::equivalent(const error_code& code, int condition) const noexcept -{ - return *this == code.category() && code.value() == condition; -} - #if !defined(_LIBCPP_HAS_NO_THREADS) namespace { @@ -167,8 +133,14 @@ const error_category& generic_category() noexcept { - static __generic_error_category s; - return s; + union GenericErrorHelper { + __generic_error_category generic_error_category; + constexpr explicit GenericErrorHelper() + : generic_error_category() {} + ~GenericErrorHelper() {} + }; + _LIBCPP_NO_DESTROY constinit static GenericErrorHelper s; + return s.generic_error_category; } class _LIBCPP_HIDDEN __system_error_category @@ -209,8 +181,15 @@ const error_category& system_category() noexcept { - static __system_error_category s; - return s; + union SystemErrorHelper { + __system_error_category system_error_category; + _LIBCPP_CONSTEXPR explicit SystemErrorHelper() + : system_error_category() {} + ~SystemErrorHelper() {} + }; + _LIBCPP_NO_DESTROY constinit + static SystemErrorHelper s; + return s.system_error_category; } // error_condition diff --git a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp --- a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp +++ b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp @@ -22,6 +22,15 @@ #include "test_macros.h" +struct A { + const std::error_category* ec; + ~A() { + std::string str = ec->name(); + assert(str == "generic") ; + } +}; +static A a; + void test_message_for_bad_value() { errno = E2BIG; // something that message will never generate const std::error_category& e_cat1 = std::generic_category(); @@ -44,5 +53,9 @@ test_message_for_bad_value(); } - return 0; + a.ec = &std::generic_category(); + std::string m2 = a.ec->name(); + assert(m2 == "generic"); + + return 0; } diff --git a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp --- a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp +++ b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp @@ -22,6 +22,15 @@ #include "test_macros.h" +struct A { + const std::error_category* ec; + ~A() { + std::string str = ec->name(); + assert(str == "system") ; + } +}; +static A a; + void test_message_for_bad_value() { errno = E2BIG; // something that message will never generate const std::error_category& e_cat1 = std::system_category(); @@ -48,5 +57,9 @@ test_message_for_bad_value(); } - return 0; + a.ec = &std::system_category(); + std::string m = a.ec->name(); + assert(m == "system"); + + return 0; } diff --git a/libcxx/test/std/input.output/iostreams.base/std.ios.manip/error.reporting/iostream_category.pass.cpp b/libcxx/test/std/input.output/iostreams.base/std.ios.manip/error.reporting/iostream_category.pass.cpp --- a/libcxx/test/std/input.output/iostreams.base/std.ios.manip/error.reporting/iostream_category.pass.cpp +++ b/libcxx/test/std/input.output/iostreams.base/std.ios.manip/error.reporting/iostream_category.pass.cpp @@ -16,11 +16,24 @@ #include "test_macros.h" +struct A { + const std::error_category* ec; + ~A() { + std::string str = ec->name(); + assert(str == "iostream") ; + } +}; +static A a; + int main(int, char**) { const std::error_category& e_cat1 = std::iostream_category(); std::string m1 = e_cat1.name(); assert(m1 == "iostream"); - return 0; + a.ec = &std::iostream_category(); + std::string m2 = a.ec->name(); + assert(m2 == "iostream"); + + return 0; } diff --git a/libcxx/test/std/thread/futures/futures.errors/future_category.pass.cpp b/libcxx/test/std/thread/futures/futures.errors/future_category.pass.cpp --- a/libcxx/test/std/thread/futures/futures.errors/future_category.pass.cpp +++ b/libcxx/test/std/thread/futures/futures.errors/future_category.pass.cpp @@ -18,10 +18,21 @@ #include "test_macros.h" +struct A { + const std::error_category* ec; + ~A() { + assert(std::strcmp(ec->name(), "future") == 0); + } +}; +static A a; + int main(int, char**) { const std::error_category& ec = std::future_category(); assert(std::strcmp(ec.name(), "future") == 0); - return 0; + a.ec = &std::future_category(); + assert(std::strcmp(a.ec->name(), "future") == 0); + + return 0; }