From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id D18313857C4E; Thu, 23 Sep 2021 15:08:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D18313857C4E MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-3860] libstdc++: Improvements to standard error category objects X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: ce01e2e64c340dadb55a8a24c545a13e654804d4 X-Git-Newrev: dd396a321be5099536af36e64454c1fcf9d67e12 Message-Id: <20210923150836.D18313857C4E@sourceware.org> Date: Thu, 23 Sep 2021 15:08:36 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Sep 2021 15:08:36 -0000 https://gcc.gnu.org/g:dd396a321be5099536af36e64454c1fcf9d67e12 commit r12-3860-gdd396a321be5099536af36e64454c1fcf9d67e12 Author: Jonathan Wakely Date: Wed Sep 22 13:56:21 2021 +0100 libstdc++: Improvements to standard error category objects This ensures that the objects returned by std::generic_category() and std::system_category() are initialized before any code starts executing, and are not destroyed at the end of the program. This means it is always safe to access them, even during startup and termination. See LWG 2992 and P1195R0 for further discussion of this. Additionally, make the types of those objects final, which might potentially allow additional devirtualization opportunities. The types are not visible to users, so there is no way they can derive from them, so making them final has no semantic change. Finally, add overrides for equivalent(int, const error_condition&) to those types, to avoid the second virtual call that would be performed by the base class definition of the function. Because we know what default_error_condition(int) does for the derived type, we don't need to make a virtual call. Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: * src/c++11/system_error.cc (generic_error_category): Define class and virtual functions as 'final'. (generic_error_category::equivalent(int, const error_condition&)): Override. (system_error_category): Define class and virtual functions as 'final'. (system_error_category::equivalent(int, const error_condition&)): Override. (generic_category_instance, system_category_instance): Use constinit union to make the objects immortal. Diff: --- libstdc++-v3/src/c++11/system_error.cc | 63 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/libstdc++-v3/src/c++11/system_error.cc b/libstdc++-v3/src/c++11/system_error.cc index 6c79202eb0e..7fc178a4deb 100644 --- a/libstdc++-v3/src/c++11/system_error.cc +++ b/libstdc++-v3/src/c++11/system_error.cc @@ -36,39 +36,58 @@ namespace { using std::string; - struct generic_error_category : public std::error_category + template + struct constant_init + { + union { + unsigned char unused; + T obj; + }; + constexpr constant_init() : obj() { } + + ~constant_init() { /* do nothing, union member is not destroyed */ } + }; + + struct generic_error_category final : public std::error_category { - virtual const char* - name() const noexcept + const char* + name() const noexcept final { return "generic"; } _GLIBCXX_DEFAULT_ABI_TAG - virtual string - message(int i) const + string + message(int i) const final { // XXX locale issues: how does one get or set loc. // _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc) return string(strerror(i)); } + + // Override this to avoid a virtual call to default_error_condition(i). + bool + equivalent(int i, const std::error_condition& cond) const noexcept final + { return i == cond.value() && *this == cond.category(); } }; - struct system_error_category : public std::error_category + __constinit constant_init generic_category_instance{}; + + struct system_error_category final : public std::error_category { - virtual const char* - name() const noexcept + const char* + name() const noexcept final { return "system"; } _GLIBCXX_DEFAULT_ABI_TAG - virtual string - message(int i) const + string + message(int i) const final { // XXX locale issues: how does one get or set loc. // _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc) return string(strerror(i)); } - virtual std::error_condition - default_error_condition(int ev) const noexcept + std::error_condition + default_error_condition(int ev) const noexcept final { // Use generic category for all known POSIX errno values (including zero) // and system category otherwise. @@ -79,7 +98,7 @@ namespace // They expand to integer constant expressions with type int, // and distinct positive values, suitable for use in #if directives. // POSIX adds more macros (but they're not defined on all targets, - // see config/os/*/error_constants.h), and POSIX allows + // see config/os/.../error_constants.h), and POSIX allows // EAGAIN == EWOULDBLOCK and ENOTSUP == EOPNOTSUPP. #ifdef E2BIG @@ -313,7 +332,7 @@ namespace case EXDEV: #endif case 0: - return std::error_condition(ev, std::generic_category()); + return std::error_condition(ev, generic_category_instance.obj); /* Additional system-dependent mappings from non-standard error codes * to one of the POSIX values above would go here, e.g. @@ -322,13 +341,17 @@ namespace */ default: - return std::error_condition(ev, std::system_category()); + return std::error_condition(ev, *this); } } + + // Override this to avoid a virtual call to default_error_condition(i). + bool + equivalent(int i, const std::error_condition& cond) const noexcept final + { return system_error_category::default_error_condition(i) == cond; } }; - const generic_error_category generic_category_instance{}; - const system_error_category system_category_instance{}; + __constinit constant_init system_category_instance{}; } namespace std _GLIBCXX_VISIBILITY(default) @@ -338,16 +361,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __throw_system_error(int __i __attribute__((unused))) { - _GLIBCXX_THROW_OR_ABORT(system_error(error_code(__i, generic_category()))); + _GLIBCXX_THROW_OR_ABORT(system_error(__i, generic_category_instance.obj)); } error_category::~error_category() = default; const error_category& - _V2::system_category() noexcept { return system_category_instance; } + _V2::system_category() noexcept { return system_category_instance.obj; } const error_category& - _V2::generic_category() noexcept { return generic_category_instance; } + _V2::generic_category() noexcept { return generic_category_instance.obj; } system_error::~system_error() = default;