From a9baab299fb37a4938d7fe5f00db19c7a3e0da53 Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Fri, 5 Sep 2025 23:31:26 +0000 Subject: [PATCH] Use underlying type for enums in is_signed/is_unsigned. With clang >= 21, using is_signed/is_unsigned with "small" enums (having an underlying type smaller than an int) results in strong error, after being reported as warnings for years (see #171). Since boost::is_signed/is_unsigned differs explicitly from the std one, and can return "true" for enums (contrary to the std one), keep this boost behavior and implement a special check for enums. This allows in particular boost::lexical_cast to keep working when converting non-scoped enums from int to strings with clang >= 21, see boostorg/lexical_cast#87). --- include/boost/type_traits/is_signed.hpp | 20 +++++++++++++++++--- include/boost/type_traits/is_unsigned.hpp | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/boost/type_traits/is_signed.hpp b/include/boost/type_traits/is_signed.hpp index 4d50bf8c6f..2ba96492ab 100644 --- a/include/boost/type_traits/is_signed.hpp +++ b/include/boost/type_traits/is_signed.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace boost { @@ -25,6 +26,18 @@ namespace boost { namespace detail{ +template +struct is_signed_values_underlying_type +{ + typedef no_cv_t underlying_type; +}; + +template +struct is_signed_values_underlying_type +{ + typedef typename ::boost::underlying_type::type underlying_type; +}; + template struct is_signed_values { @@ -34,14 +47,15 @@ struct is_signed_values // the correct answer. // typedef typename remove_cv::type no_cv_t; - static const no_cv_t minus_one = (static_cast(-1)); - static const no_cv_t zero = (static_cast(0)); + typedef typename is_signed_values_underlying_type::value>::underlying_type underlying_type; + + static const underlying_type minus_one = (static_cast(-1)); + static const underlying_type zero = (static_cast(0)); }; template struct is_signed_helper { - typedef typename remove_cv::type no_cv_t; BOOST_STATIC_CONSTANT(bool, value = (!(::boost::detail::is_signed_values::minus_one > boost::detail::is_signed_values::zero))); }; diff --git a/include/boost/type_traits/is_unsigned.hpp b/include/boost/type_traits/is_unsigned.hpp index 38b916296d..34e4e16f13 100644 --- a/include/boost/type_traits/is_unsigned.hpp +++ b/include/boost/type_traits/is_unsigned.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -26,6 +27,18 @@ namespace boost { namespace detail{ +template +struct is_unsigned_values_underlying_type +{ + typedef no_cv_t underlying_type; +}; + +template +struct is_unsigned_values_underlying_type +{ + typedef typename ::boost::underlying_type::type underlying_type; +}; + template struct is_unsigned_values { @@ -35,8 +48,10 @@ struct is_unsigned_values // the correct answer. // typedef typename remove_cv::type no_cv_t; - static const no_cv_t minus_one = (static_cast(-1)); - static const no_cv_t zero = (static_cast(0)); + typedef typename is_unsigned_values_underlying_type::value>::underlying_type underlying_type; + + static const underlying_type minus_one = (static_cast(-1)); + static const underlying_type zero = (static_cast(0)); }; template