Skip to content

Conversation

@Romain-Geissler-1A
Copy link

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).

@Romain-Geissler-1A
Copy link
Author

Ping

1 similar comment
@Romain-Geissler-1A
Copy link
Author

Ping

@jzmaddock
Copy link
Collaborator

The problem you have here, is that underlying_type gets instantiated unconditionally regardless of the argument, or whether the result is used.

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 boostorg#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).
@Romain-Geissler-1A Romain-Geissler-1A force-pushed the fix-is_signed-with-enum-and-clang-21 branch from aca9782 to a9baab2 Compare October 31, 2025 14:58
@Romain-Geissler-1A
Copy link
Author

@jzmaddock I changed a bit the definition, to now use underlying_type only for enums.

@lolipodass
Copy link

Ping

1 similar comment
@Romain-Geissler-1A
Copy link
Author

Ping

freebsd-git pushed a commit to freebsd/freebsd-ports that referenced this pull request Jan 1, 2026
Recent versions of clang made -Wenum-constexpr-conversion errors into a
hard error, as was announced several versions ago.

Boost type_traits has two instances where it attempts to convert
out-of-range enum values, leading to errors similar to:

    In file included from ../src/lib/dhcpsrv/csv_lease_file6.cc:9:
    In file included from ../src/lib/dhcpsrv/dhcpsrv_log.h:11:
    In file included from ../src/lib/log/macros.h:10:
    In file included from ../src/lib/log/logger.h:19:
    In file included from ../src/lib/log/log_formatter.h:19:
    In file included from /usr/local/include/boost/lexical_cast.hpp:33:
    In file included from /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:31:
    In file included from /usr/local/include/boost/lexical_cast/detail/converter_numeric.hpp:31:
    In file included from /usr/local/include/boost/type_traits/make_unsigned.hpp:14:
    /usr/local/include/boost/type_traits/is_signed.hpp:37:25: error: in-class initializer for static data member is not a constant expression
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                         ^           ~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/local/include/boost/type_traits/is_signed.hpp:45:60: note: in instantiation of template class 'boost::detail::is_signed_values<isc::dhcp::Lease::Type>' requested here
       45 |    BOOST_STATIC_CONSTANT(bool, value = (!(::boost::detail::is_signed_values<T>::minus_one  > boost::detail::is_signed_values<T>::zero)));
          |                                                            ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:74:40: note: in instantiation of template class 'boost::detail::is_signed_helper<isc::dhcp::Lease::Type>' requested here
       74 |    BOOST_STATIC_CONSTANT(bool, value = type::value);
          |                                        ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:79:85: note: in instantiation of template class 'boost::detail::is_signed_impl<isc::dhcp::Lease::Type>' requested here
       79 | template <class T> struct is_signed : public integral_constant<bool, boost::detail::is_signed_impl<T>::value> {};
          |                                                                                     ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical_streams.hpp:315:44: note: in instantiation of template class 'boost::is_signed<isc::dhcp::Lease::Type>' requested here
      315 |         typename boost::enable_if_c<boost::is_signed<Type>::value && !boost::is_enum<Type>::value, bool>::type
          |                                            ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:449:67: note: while substituting deduced template arguments into function template 'stream_in' [with Type = isc::dhcp::Lease::Type]
      449 |                 -> decltype(std::declval<optimized_src_stream&>().stream_in(std::declval<lcast::exact<T>>()), optimized_src_stream{});
          |                                                                   ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:454:46: note: while substituting explicitly-specified template arguments into function template 'detect_type'
      454 |             using from_src_stream = decltype(detect_type<Source>(1));
          |                                              ^
    /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:67:20: note: in instantiation of template class 'boost::detail::lexical_converter_impl<std::string, isc::dhcp::Lease::Type>' requested here
       67 |             return caster_type::try_convert(arg, result);
          |                    ^
    /usr/local/include/boost/lexical_cast.hpp:42:41: note: in instantiation of function template specialization 'boost::conversion::detail::try_lexical_convert<std::string, isc::dhcp::Lease::Type>' requested here
       42 |         if (!boost::conversion::detail::try_lexical_convert(arg, result)) {
          |                                         ^
    ../src/lib/util/csv_file.h:243:34: note: in instantiation of function template specialization 'boost::lexical_cast<std::string, isc::dhcp::Lease::Type>' requested here
      243 |             values_[at] = boost::lexical_cast<std::string>(value);
          |                                  ^
    ../src/lib/dhcpsrv/csv_lease_file6.cc:54:9: note: in instantiation of function template specialization 'isc::util::CSVRow::writeAt<isc::dhcp::Lease::Type>' requested here
       54 |     row.writeAt(getColumnIndex("lease_type"), lease.type_);
          |         ^
    /usr/local/include/boost/type_traits/is_signed.hpp:37:38: note: integer value -1 is outside the valid range of values [0, 3] for the enumeration type 'Type'
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                                      ^

This is while compiling net/kea, but other users of boost type traits
may also have the same issue.

There is an upstream bug report at:
boostorg/type_traits#202

and an outstanding pull request at:
boostorg/type_traits#199

Apply the latter as a diff, to work around the problem. Bump
PORTREVISION to make dependents recompile.

PR:		292071
Approved by:	fluffy (maintainer)
MFH:		2025Q4
freebsd-git pushed a commit to freebsd/freebsd-ports that referenced this pull request Jan 1, 2026
Recent versions of clang made -Wenum-constexpr-conversion errors into a
hard error, as was announced several versions ago.

Boost type_traits has two instances where it attempts to convert
out-of-range enum values, leading to errors similar to:

    In file included from ../src/lib/dhcpsrv/csv_lease_file6.cc:9:
    In file included from ../src/lib/dhcpsrv/dhcpsrv_log.h:11:
    In file included from ../src/lib/log/macros.h:10:
    In file included from ../src/lib/log/logger.h:19:
    In file included from ../src/lib/log/log_formatter.h:19:
    In file included from /usr/local/include/boost/lexical_cast.hpp:33:
    In file included from /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:31:
    In file included from /usr/local/include/boost/lexical_cast/detail/converter_numeric.hpp:31:
    In file included from /usr/local/include/boost/type_traits/make_unsigned.hpp:14:
    /usr/local/include/boost/type_traits/is_signed.hpp:37:25: error: in-class initializer for static data member is not a constant expression
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                         ^           ~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/local/include/boost/type_traits/is_signed.hpp:45:60: note: in instantiation of template class 'boost::detail::is_signed_values<isc::dhcp::Lease::Type>' requested here
       45 |    BOOST_STATIC_CONSTANT(bool, value = (!(::boost::detail::is_signed_values<T>::minus_one  > boost::detail::is_signed_values<T>::zero)));
          |                                                            ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:74:40: note: in instantiation of template class 'boost::detail::is_signed_helper<isc::dhcp::Lease::Type>' requested here
       74 |    BOOST_STATIC_CONSTANT(bool, value = type::value);
          |                                        ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:79:85: note: in instantiation of template class 'boost::detail::is_signed_impl<isc::dhcp::Lease::Type>' requested here
       79 | template <class T> struct is_signed : public integral_constant<bool, boost::detail::is_signed_impl<T>::value> {};
          |                                                                                     ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical_streams.hpp:315:44: note: in instantiation of template class 'boost::is_signed<isc::dhcp::Lease::Type>' requested here
      315 |         typename boost::enable_if_c<boost::is_signed<Type>::value && !boost::is_enum<Type>::value, bool>::type
          |                                            ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:449:67: note: while substituting deduced template arguments into function template 'stream_in' [with Type = isc::dhcp::Lease::Type]
      449 |                 -> decltype(std::declval<optimized_src_stream&>().stream_in(std::declval<lcast::exact<T>>()), optimized_src_stream{});
          |                                                                   ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:454:46: note: while substituting explicitly-specified template arguments into function template 'detect_type'
      454 |             using from_src_stream = decltype(detect_type<Source>(1));
          |                                              ^
    /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:67:20: note: in instantiation of template class 'boost::detail::lexical_converter_impl<std::string, isc::dhcp::Lease::Type>' requested here
       67 |             return caster_type::try_convert(arg, result);
          |                    ^
    /usr/local/include/boost/lexical_cast.hpp:42:41: note: in instantiation of function template specialization 'boost::conversion::detail::try_lexical_convert<std::string, isc::dhcp::Lease::Type>' requested here
       42 |         if (!boost::conversion::detail::try_lexical_convert(arg, result)) {
          |                                         ^
    ../src/lib/util/csv_file.h:243:34: note: in instantiation of function template specialization 'boost::lexical_cast<std::string, isc::dhcp::Lease::Type>' requested here
      243 |             values_[at] = boost::lexical_cast<std::string>(value);
          |                                  ^
    ../src/lib/dhcpsrv/csv_lease_file6.cc:54:9: note: in instantiation of function template specialization 'isc::util::CSVRow::writeAt<isc::dhcp::Lease::Type>' requested here
       54 |     row.writeAt(getColumnIndex("lease_type"), lease.type_);
          |         ^
    /usr/local/include/boost/type_traits/is_signed.hpp:37:38: note: integer value -1 is outside the valid range of values [0, 3] for the enumeration type 'Type'
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                                      ^

This is while compiling net/kea, but other users of boost type traits
may also have the same issue.

There is an upstream bug report at:
boostorg/type_traits#202

and an outstanding pull request at:
boostorg/type_traits#199

Apply the latter as a diff, to work around the problem. Bump
PORTREVISION to make dependents recompile.

PR:		292071
Approved by:	fluffy (maintainer)
MFH:		2025Q4

(cherry picked from commit ab93476)
fluffykhv pushed a commit to fluffykhv/freebsd-ports-boost that referenced this pull request Jan 1, 2026
Recent versions of clang made -Wenum-constexpr-conversion errors into a
hard error, as was announced several versions ago.

Boost type_traits has two instances where it attempts to convert
out-of-range enum values, leading to errors similar to:

    In file included from ../src/lib/dhcpsrv/csv_lease_file6.cc:9:
    In file included from ../src/lib/dhcpsrv/dhcpsrv_log.h:11:
    In file included from ../src/lib/log/macros.h:10:
    In file included from ../src/lib/log/logger.h:19:
    In file included from ../src/lib/log/log_formatter.h:19:
    In file included from /usr/local/include/boost/lexical_cast.hpp:33:
    In file included from /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:31:
    In file included from /usr/local/include/boost/lexical_cast/detail/converter_numeric.hpp:31:
    In file included from /usr/local/include/boost/type_traits/make_unsigned.hpp:14:
    /usr/local/include/boost/type_traits/is_signed.hpp:37:25: error: in-class initializer for static data member is not a constant expression
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                         ^           ~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/local/include/boost/type_traits/is_signed.hpp:45:60: note: in instantiation of template class 'boost::detail::is_signed_values<isc::dhcp::Lease::Type>' requested here
       45 |    BOOST_STATIC_CONSTANT(bool, value = (!(::boost::detail::is_signed_values<T>::minus_one  > boost::detail::is_signed_values<T>::zero)));
          |                                                            ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:74:40: note: in instantiation of template class 'boost::detail::is_signed_helper<isc::dhcp::Lease::Type>' requested here
       74 |    BOOST_STATIC_CONSTANT(bool, value = type::value);
          |                                        ^
    /usr/local/include/boost/config/detail/suffix.hpp:410:72: note: expanded from macro 'BOOST_STATIC_CONSTANT'
      410 | #     define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment
          |                                                                        ^
    /usr/local/include/boost/type_traits/is_signed.hpp:79:85: note: in instantiation of template class 'boost::detail::is_signed_impl<isc::dhcp::Lease::Type>' requested here
       79 | template <class T> struct is_signed : public integral_constant<bool, boost::detail::is_signed_impl<T>::value> {};
          |                                                                                     ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical_streams.hpp:315:44: note: in instantiation of template class 'boost::is_signed<isc::dhcp::Lease::Type>' requested here
      315 |         typename boost::enable_if_c<boost::is_signed<Type>::value && !boost::is_enum<Type>::value, bool>::type
          |                                            ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:449:67: note: while substituting deduced template arguments into function template 'stream_in' [with Type = isc::dhcp::Lease::Type]
      449 |                 -> decltype(std::declval<optimized_src_stream&>().stream_in(std::declval<lcast::exact<T>>()), optimized_src_stream{});
          |                                                                   ^
    /usr/local/include/boost/lexical_cast/detail/converter_lexical.hpp:454:46: note: while substituting explicitly-specified template arguments into function template 'detect_type'
      454 |             using from_src_stream = decltype(detect_type<Source>(1));
          |                                              ^
    /usr/local/include/boost/lexical_cast/try_lexical_convert.hpp:67:20: note: in instantiation of template class 'boost::detail::lexical_converter_impl<std::string, isc::dhcp::Lease::Type>' requested here
       67 |             return caster_type::try_convert(arg, result);
          |                    ^
    /usr/local/include/boost/lexical_cast.hpp:42:41: note: in instantiation of function template specialization 'boost::conversion::detail::try_lexical_convert<std::string, isc::dhcp::Lease::Type>' requested here
       42 |         if (!boost::conversion::detail::try_lexical_convert(arg, result)) {
          |                                         ^
    ../src/lib/util/csv_file.h:243:34: note: in instantiation of function template specialization 'boost::lexical_cast<std::string, isc::dhcp::Lease::Type>' requested here
      243 |             values_[at] = boost::lexical_cast<std::string>(value);
          |                                  ^
    ../src/lib/dhcpsrv/csv_lease_file6.cc:54:9: note: in instantiation of function template specialization 'isc::util::CSVRow::writeAt<isc::dhcp::Lease::Type>' requested here
       54 |     row.writeAt(getColumnIndex("lease_type"), lease.type_);
          |         ^
    /usr/local/include/boost/type_traits/is_signed.hpp:37:38: note: integer value -1 is outside the valid range of values [0, 3] for the enumeration type 'Type'
       37 |    static const no_cv_t minus_one = (static_cast<no_cv_t>(-1));
          |                                      ^

This is while compiling net/kea, but other users of boost type traits
may also have the same issue.

There is an upstream bug report at:
boostorg/type_traits#202

and an outstanding pull request at:
boostorg/type_traits#199

Apply the latter as a diff, to work around the problem. Bump
PORTREVISION to make dependents recompile.

PR:		292071
Approved by:	fluffy (maintainer)
MFH:		2025Q4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants