Hello! I've prepared a patch, which adds all members missing from std::numeric_limits<> specializations for integer-class types.
Jonathan, please let me know whether you like these changes and do not see any bugs or issues with them. From my side, I just want to say that: - Since all std::numeric_limits<> specializations for integral types, defined in //libstdc++-v3/include/std/limits don't inherit from a base class providing common data members and member functions, I also didn't introduce such a base class in //libstdc++-v3/include/bits/max_size_type.h. Such implementation has quite a bit of code duplication, but it's like that on purpose, right? - I didn't test the traps static data member, because I don't know how to accurately predict when this compile-time constant should be true and when it should be false. Moreover, I saw that the unit-test verifying correctness of the traps constant from std::numeric_limits<> specializations for integral types (//libstdc++-v3/testsuite/18_support/numeric_limits/traps.cc) also doesn't verify its value. - In the unit-tests for integer-class types I've defined variable template verify_numeric_limits_values_not_meaningful_for<> to avoid code duplication and have clear and readable code. I hope this is OK. Thanks, Mateusz Zych On Wed, Jul 2, 2025 at 7:30 PM Jonathan Wakely <jwak...@redhat.com> wrote: > On Wed, 2 Jul 2025 at 17:15, Mateusz Zych wrote: > > > > OK, then I’ll prepare appropriate patch with tests and send it when I’m > done implementing it. > > That would be great, thanks. I won't push the initial patch, we can > wait for you to prepare the complete fix. > > Please note that for a more significant change, we have some legal > prerequisites for contributions, as documented at: > https://gcc.gnu.org/contribute.html#legal > > If you want to contribute under the DCO terms, please read > https://gcc.gnu.org/dco.html so that you understand exactly what the > Signed-off-by: trailer means. > > Thanks! > >
From d7d20d31e549e001f7644ee53899fa8494d0700f Mon Sep 17 00:00:00 2001 From: Mateusz Zych <mte.z...@gmail.com> Date: Wed, 2 Jul 2025 01:51:40 +0300 Subject: [PATCH] libstdc++: Added missing members to numeric_limits specializations for integer-class types. 25.3.4.4 Concept weakly_incrementable [iterator.concept.winc] (5) For every integer-class type I, let B(I) be a unique hypothetical extended integer type of the same signedness with the same width as I. [Note 2: The corresponding hypothetical specialization numeric_limits<B(I)> meets the requirements on numeric_limits specializations for integral types.] (11) For every (possibly cv-qualified) integer-class type I, numeric_limits<I> is specialized such that: - each static data member m has the same value as numeric_limits<B(I)>::m, and - each static member function f returns I(numeric_limits<B(I)>::f()). 17.3.5.3 numeric_limits specializations [numeric.special] (1) All members shall be provided for all specializations. However, many values are only required to be meaningful under certain conditions (for example, epsilon() is only meaningful if is_integer is false). Any value that is not meaningful shall be set to 0 or false. libstdc++-v3/ChangeLog: * include/bits/max_size_type.h (numeric_limits<__max_size_type>): New static data members. (numeric_limits<__max_diff_type>): Likewise. Signed-off-by: Mateusz Zych <mte.z...@gmail.com> --- libstdc++-v3/include/bits/max_size_type.h | 83 +++++++++++++++++++ .../std/ranges/iota/max_size_type.cc | 31 +++++++ 2 files changed, 114 insertions(+) diff --git a/libstdc++-v3/include/bits/max_size_type.h b/libstdc++-v3/include/bits/max_size_type.h index 73a6d141d5b..30c5b124767 100644 --- a/libstdc++-v3/include/bits/max_size_type.h +++ b/libstdc++-v3/include/bits/max_size_type.h @@ -38,6 +38,7 @@ #include <ext/numeric_traits.h> #include <bit> // __bit_width #include <numbers> +#include <limits> // __glibcxx_integral_traps // This header implements unsigned and signed integer-class types (as per // [iterator.concept.winc]) that are one bit wider than the widest supported @@ -775,10 +776,27 @@ namespace ranges static constexpr bool is_signed = false; static constexpr bool is_integer = true; static constexpr bool is_exact = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr int radix = 2; static constexpr int digits = __gnu_cxx::__int_traits<_Sp::__rep>::__digits + 1; static constexpr int digits10 = static_cast<int>(digits * numbers::ln2 / numbers::ln10); + static constexpr int max_digits10 = 0; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool is_iec559 = false; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr bool has_denorm_loss = false; + static constexpr bool tinyness_before = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr float_round_style round_style = round_toward_zero; static constexpr _Sp min() noexcept @@ -791,6 +809,30 @@ namespace ranges static constexpr _Sp lowest() noexcept { return min(); } + + static constexpr _Sp + denorm_min() noexcept + { return 0; } + + static constexpr _Sp + epsilon() noexcept + { return 0; } + + static constexpr _Sp + round_error() noexcept + { return 0; } + + static constexpr _Sp + infinity() noexcept + { return 0; } + + static constexpr _Sp + quiet_NaN() noexcept + { return 0; } + + static constexpr _Sp + signaling_NaN() noexcept + { return 0; } }; template<> @@ -802,9 +844,26 @@ namespace ranges static constexpr bool is_signed = true; static constexpr bool is_integer = true; static constexpr bool is_exact = true; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr int radix = 2; static constexpr int digits = numeric_limits<_Sp>::digits - 1; static constexpr int digits10 = static_cast<int>(digits * numbers::ln2 / numbers::ln10); + static constexpr int max_digits10 = 0; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool is_iec559 = false; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr bool has_denorm_loss = false; + static constexpr bool tinyness_before = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr float_round_style round_style = round_toward_zero; static constexpr _Dp min() noexcept @@ -817,6 +876,30 @@ namespace ranges static constexpr _Dp lowest() noexcept { return min(); } + + static constexpr _Dp + denorm_min() noexcept + { return 0; } + + static constexpr _Dp + epsilon() noexcept + { return 0; } + + static constexpr _Dp + round_error() noexcept + { return 0; } + + static constexpr _Dp + infinity() noexcept + { return 0; } + + static constexpr _Dp + quiet_NaN() noexcept + { return 0; } + + static constexpr _Dp + signaling_NaN() noexcept + { return 0; } }; template<> diff --git a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc index 4739d9e2f79..fbd783bdf1a 100644 --- a/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc +++ b/libstdc++-v3/testsuite/std/ranges/iota/max_size_type.cc @@ -352,6 +352,9 @@ static_assert(numeric_limits<max_size_t>::is_specialized); static_assert(!numeric_limits<max_size_t>::is_signed); static_assert(numeric_limits<max_size_t>::is_integer); static_assert(numeric_limits<max_size_t>::is_exact); +static_assert(numeric_limits<max_size_t>::is_bounded); +static_assert(numeric_limits<max_size_t>::is_modulo); +static_assert(numeric_limits<max_size_t>::radix == 2); // We can't unconditionally use numeric_limits here because __int128 is an // integral type only in GNU mode. #if __SIZEOF_INT128__ @@ -379,6 +382,9 @@ static_assert(numeric_limits<max_diff_t>::is_specialized); static_assert(numeric_limits<max_diff_t>::is_signed); static_assert(numeric_limits<max_diff_t>::is_integer); static_assert(numeric_limits<max_diff_t>::is_exact); +static_assert(numeric_limits<max_diff_t>::is_bounded); +static_assert(!numeric_limits<max_diff_t>::is_modulo); +static_assert(numeric_limits<max_diff_t>::radix == 2); static_assert(numeric_limits<max_diff_t>::digits == numeric_limits<max_size_t>::digits - 1); static_assert(numeric_limits<max_diff_t>::digits10 @@ -400,6 +406,31 @@ static_assert(max_diff_t(max_size_t(1) << (numeric_limits<max_size_t>::digits-1)) == numeric_limits<max_diff_t>::min()); +template <typename integer_class> +constexpr bool verify_numeric_limits_values_not_meaningful_for = true + && (numeric_limits<integer_class>::max_digits10 == 0) + && (numeric_limits<integer_class>::min_exponent == 0) + && (numeric_limits<integer_class>::min_exponent10 == 0) + && (numeric_limits<integer_class>::max_exponent == 0) + && (numeric_limits<integer_class>::max_exponent10 == 0) + && !numeric_limits<integer_class>::is_iec559 + && !numeric_limits<integer_class>::has_infinity + && !numeric_limits<integer_class>::has_quiet_NaN + && !numeric_limits<integer_class>::has_signaling_NaN + && !numeric_limits<integer_class>::has_denorm_loss + && !numeric_limits<integer_class>::tinyness_before + && (numeric_limits<integer_class>::has_denorm == std::denorm_absent) + && (numeric_limits<integer_class>::round_style == std::round_toward_zero) + && (numeric_limits<integer_class>::denorm_min() == 0) + && (numeric_limits<integer_class>::epsilon() == 0) + && (numeric_limits<integer_class>::round_error() == 0) + && (numeric_limits<integer_class>::infinity() == 0) + && (numeric_limits<integer_class>::quiet_NaN() == 0) + && (numeric_limits<integer_class>::signaling_NaN() == 0); + +static_assert(verify_numeric_limits_values_not_meaningful_for<max_size_t>); +static_assert(verify_numeric_limits_values_not_meaningful_for<max_diff_t>); + // Verify that the types are structural types and can therefore be used // as NTTP types. template<max_size_t V> struct Su { static_assert(V*V == V+132); }; -- 2.48.1