Hello!

I've updated the ChangeLog, since I forgot to do it before.

Thanks, Mateusz Zych

On Thu, Jul 3, 2025 at 9:49 PM Mateusz Zych <mte.z...@gmail.com> wrote:

> 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 04d48ce85f8b7bb40bb3f89bbdcdecd0458071fc 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 members.
	(numeric_limits<__max_diff_type>): Likewise.
	* testsuite/std/ranges/iota/max_size_type.cc: New test cases.

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

Reply via email to