From af53f17a2742e20c8aa068b87f62f3222f4a26a3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sun, 15 Feb 2026 19:28:43 +0200 Subject: [PATCH] Add constexpr to virtual functions on C++20 or later. Refs #141. --- include/boost/system/detail/config.hpp | 12 +++++ .../boost/system/detail/error_category.hpp | 26 ++++----- .../system/detail/error_category_impl.hpp | 10 ++-- test/CMakeLists.txt | 2 + test/Jamfile.v2 | 2 + test/failed_constexpr_test2.cpp | 54 +++++++++++++++++++ 6 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 test/failed_constexpr_test2.cpp diff --git a/include/boost/system/detail/config.hpp b/include/boost/system/detail/config.hpp index c231f0d..17af8ce 100644 --- a/include/boost/system/detail/config.hpp +++ b/include/boost/system/detail/config.hpp @@ -38,6 +38,18 @@ # define BOOST_SYSTEM_CONSTEXPR #endif +// BOOST_SYSTEM_HAS_CXX20_CONSTEXPR + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L +# define BOOST_SYSTEM_HAS_CXX20_CONSTEXPR +#endif + +#if defined(BOOST_SYSTEM_HAS_CXX20_CONSTEXPR) +# define BOOST_SYSTEM_CXX20_CONSTEXPR constexpr +#else +# define BOOST_SYSTEM_CXX20_CONSTEXPR +#endif + // BOOST_SYSTEM_DEPRECATED #if defined(__clang__) diff --git a/include/boost/system/detail/error_category.hpp b/include/boost/system/detail/error_category.hpp index e704221..84dec99 100644 --- a/include/boost/system/detail/error_category.hpp +++ b/include/boost/system/detail/error_category.hpp @@ -94,31 +94,31 @@ protected: public: - virtual const char * name() const noexcept = 0; + virtual const char* name() const noexcept = 0; - virtual error_condition default_error_condition( int ev ) const noexcept; - virtual bool equivalent( int code, const error_condition & condition ) const noexcept; - virtual bool equivalent( const error_code & code, int condition ) const noexcept; + BOOST_SYSTEM_CXX20_CONSTEXPR virtual error_condition default_error_condition( int ev ) const noexcept; + BOOST_SYSTEM_CXX20_CONSTEXPR virtual bool equivalent( int code, error_condition const& condition ) const noexcept; + BOOST_SYSTEM_CXX20_CONSTEXPR virtual bool equivalent( error_code const& code, int condition ) const noexcept; virtual std::string message( int ev ) const = 0; - virtual char const * message( int ev, char * buffer, std::size_t len ) const noexcept; + virtual char const* message( int ev, char* buffer, std::size_t len ) const noexcept; - virtual bool failed( int ev ) const noexcept + BOOST_SYSTEM_CXX20_CONSTEXPR virtual bool failed( int ev ) const noexcept { return ev != 0; } - friend BOOST_SYSTEM_CONSTEXPR bool operator==( error_category const & lhs, error_category const & rhs ) noexcept + friend BOOST_SYSTEM_CONSTEXPR bool operator==( error_category const& lhs, error_category const& rhs ) noexcept { return rhs.id_ == 0? &lhs == &rhs: lhs.id_ == rhs.id_; } - friend BOOST_SYSTEM_CONSTEXPR bool operator!=( error_category const & lhs, error_category const & rhs ) noexcept + friend BOOST_SYSTEM_CONSTEXPR bool operator!=( error_category const& lhs, error_category const& rhs ) noexcept { return !( lhs == rhs ); } - friend BOOST_SYSTEM_CONSTEXPR bool operator<( error_category const & lhs, error_category const & rhs ) noexcept + friend BOOST_SYSTEM_CONSTEXPR bool operator<( error_category const& lhs, error_category const& rhs ) noexcept { if( lhs.id_ < rhs.id_ ) { @@ -135,15 +135,15 @@ public: return false; // equal } - return std::less()( &lhs, &rhs ); + return std::less()( &lhs, &rhs ); } void init_stdcat() const; # if defined(__SUNPRO_CC) // trailing __global is not supported - operator std::error_category const & () const; + operator std::error_category const& () const; # else - operator std::error_category const & () const BOOST_SYMBOL_VISIBLE; + operator std::error_category const& () const BOOST_SYMBOL_VISIBLE; # endif }; @@ -162,7 +162,7 @@ static const boost::ulong_long_type generic_category_id = ( boost::ulong_long_ty static const boost::ulong_long_type system_category_id = generic_category_id + 1; static const boost::ulong_long_type interop_category_id = generic_category_id + 2; -BOOST_SYSTEM_CONSTEXPR inline bool failed_impl( int ev, error_category const & cat ) +BOOST_SYSTEM_CONSTEXPR inline bool failed_impl( int ev, error_category const& cat ) { if( cat.id_ == system_category_id || cat.id_ == generic_category_id ) { diff --git a/include/boost/system/detail/error_category_impl.hpp b/include/boost/system/detail/error_category_impl.hpp index 7d69f71..2162c4c 100644 --- a/include/boost/system/detail/error_category_impl.hpp +++ b/include/boost/system/detail/error_category_impl.hpp @@ -26,22 +26,22 @@ namespace system // error_category default implementation -inline error_condition error_category::default_error_condition( int ev ) const noexcept +BOOST_SYSTEM_CXX20_CONSTEXPR inline error_condition error_category::default_error_condition( int ev ) const noexcept { return error_condition( ev, *this ); } -inline bool error_category::equivalent( int code, const error_condition & condition ) const noexcept +BOOST_SYSTEM_CXX20_CONSTEXPR inline bool error_category::equivalent( int code, error_condition const& condition ) const noexcept { return default_error_condition( code ) == condition; } -inline bool error_category::equivalent( const error_code & code, int condition ) const noexcept +BOOST_SYSTEM_CXX20_CONSTEXPR inline bool error_category::equivalent( error_code const& code, int condition ) const noexcept { return code.equals( condition, *this ); } -inline char const * error_category::message( int ev, char * buffer, std::size_t len ) const noexcept +inline char const* error_category::message( int ev, char* buffer, std::size_t len ) const noexcept { if( len == 0 ) { @@ -116,7 +116,7 @@ inline void error_category::init_stdcat() const #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif -inline BOOST_NOINLINE error_category::operator std::error_category const & () const +inline BOOST_NOINLINE error_category::operator std::error_category const& () const { if( id_ == detail::generic_category_id ) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 79734ee..c79a621 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -135,6 +135,8 @@ boost_test(TYPE run SOURCES ec_hash_value_test.cpp) boost_test(TYPE run SOURCES std_interop_test16.cpp) +boost_test(TYPE run SOURCES failed_constexpr_test2.cpp) + # result boost_test(TYPE run SOURCES result_default_construct.cpp) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 45049e1..eaa73bf 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -168,6 +168,8 @@ run ec_hash_value_test.cpp ; run std_interop_test16.cpp ; +run failed_constexpr_test2.cpp ; + # result run result_default_construct.cpp ; diff --git a/test/failed_constexpr_test2.cpp b/test/failed_constexpr_test2.cpp new file mode 100644 index 0000000..dd16d6b --- /dev/null +++ b/test/failed_constexpr_test2.cpp @@ -0,0 +1,54 @@ +// Copyright 2026 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +#if !defined(BOOST_SYSTEM_HAS_CXX20_CONSTEXPR) + +BOOST_PRAGMA_MESSAGE("Skipping constexpr test, BOOST_SYSTEM_HAS_CXX20_CONSTEXPR isn't defined") +int main() {} + +#else + +namespace sys = boost::system; + +class user_category: public sys::error_category +{ +public: + + constexpr virtual const char* name() const noexcept + { + return "user"; + } + + virtual std::string message( int ev ) const + { + char buffer[ 256 ]; + std::snprintf( buffer, sizeof( buffer ), "user message %d", ev ); + + return buffer; + } +}; + +static constexpr user_category s_user_cat; + +constexpr sys::error_code ec( 1, s_user_cat ); + +BOOST_STATIC_ASSERT( ec.failed() ); +BOOST_STATIC_ASSERT( ec ); +BOOST_STATIC_ASSERT( !!ec ); + +constexpr sys::error_condition en( 1, s_user_cat ); + +BOOST_STATIC_ASSERT( en.failed() ); +BOOST_STATIC_ASSERT( en ); +BOOST_STATIC_ASSERT( !!en ); + +int main() {} + +#endif