libstdc++: Fix weakly_incrementable to allow __int128 (PR 93267)
authorJonathan Wakely <jwakely@redhat.com>
Wed, 15 Jan 2020 14:09:35 +0000 (14:09 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 15 Jan 2020 16:22:49 +0000 (16:22 +0000)
The __iota_diff_t alias can be the type __int128, but that does not
satisfy the signed_integral and __is_signed_integer_like concepts when
__STRICT_ANSI__ is defined (which is true for -std=c++2a).

Because weakly_incrementable is defined in terms of signed_integral, it
is not satisfied by __int128, which means iota_view's iterator doesn't
always satisfy input_or_output_iterator and so iota_view is not always a
range.

The solution is to define __max_size_type and __max_diff_type using
__int128, so that __is_signed_integer_like allows __int128, and then
make weakly_incrementable use __is_signed_integer_like instead of
signed_integral.

PR libstdc++/93267
* include/bits/iterator_concepts.h (__max_diff_type, __max_size_type):
Move here from <bits/range_access.h> and define using __int128 when
available.
(__is_integer_like, __is_signed_integer_like): Move here from
<bits/range_access.h>.
(weakly_incrementable): Use __is_signed_integer_like.
* include/bits/range_access.h (__max_diff_type, __max_size_type)
(__is_integer_like, __is_signed_integer_like): Move to
<bits/iterator_concepts.h>.
(__make_unsigned_like_t): Move here from <ranges>.
* include/std/ranges (__make_unsigned_like_t): Move to
<bits/range_access.h>.
(iota_view): Replace using-directive with using-declarations.
* testsuite/std/ranges/iota/93267.cc: New test.
* testsuite/std/ranges/iota_view.cc: Move to new 'iota' sub-directory.

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/iterator_concepts.h
libstdc++-v3/include/bits/range_access.h
libstdc++-v3/include/std/ranges
libstdc++-v3/testsuite/std/ranges/iota/93267.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/ranges/iota_view.cc [deleted file]

index 626f59c65646c82fa9f247565d8182c1257b726e..29414820e12161366babd9f8ec1b5301e34dec7e 100644 (file)
@@ -1,3 +1,22 @@
+2020-01-15  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/93267
+       * include/bits/iterator_concepts.h (__max_diff_type, __max_size_type):
+       Move here from <bits/range_access.h> and define using __int128 when
+       available.
+       (__is_integer_like, __is_signed_integer_like): Move here from
+       <bits/range_access.h>.
+       (weakly_incrementable): Use __is_signed_integer_like.
+       * include/bits/range_access.h (__max_diff_type, __max_size_type)
+       (__is_integer_like, __is_signed_integer_like): Move to
+       <bits/iterator_concepts.h>.
+       (__make_unsigned_like_t): Move here from <ranges>.
+       * include/std/ranges (__make_unsigned_like_t): Move to
+       <bits/range_access.h>.
+       (iota_view): Replace using-directive with using-declarations.
+       * testsuite/std/ranges/iota/93267.cc: New test.
+       * testsuite/std/ranges/iota_view.cc: Move to new 'iota' sub-directory.
+
 2020-01-13  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/93244
index 4ba32a0859e644456e80ca10ad58cff750b7ec83..bf5815972299ea53a6e6fc95f53eb510a9d245fd 100644 (file)
@@ -492,6 +492,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          = std::forward<_Tp>(__t);
       };
 
+  namespace ranges::__detail
+  {
+#if __SIZEOF_INT128__
+    using __max_diff_type = __int128;
+    using __max_size_type = unsigned __int128;
+#else
+    using __max_diff_type = long long;
+    using __max_size_type = unsigned long long;
+#endif
+
+    template<typename _Tp>
+      concept __is_integer_like = integral<_Tp>
+       || same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>;
+
+    template<typename _Tp>
+      concept __is_signed_integer_like = signed_integral<_Tp>
+       || same_as<_Tp, __max_diff_type>;
+
+  } // namespace ranges::__detail
+
+  namespace __detail { using ranges::__detail::__is_signed_integer_like; }
+
   /// Requirements on types that can be incremented with ++.
   template<typename _Iter>
     concept weakly_incrementable = default_initializable<_Iter>
@@ -499,7 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       && requires(_Iter __i)
       {
        typename iter_difference_t<_Iter>;
-       requires signed_integral<iter_difference_t<_Iter>>;
+       requires __detail::__is_signed_integer_like<iter_difference_t<_Iter>>;
        { ++__i } -> same_as<_Iter&>;
        __i++;
       };
index 721c755f48c2672fc2f94829ff212493c3456730..8b546a588405a500c96e01f6ab85b228e7fd6ded 100644 (file)
@@ -347,22 +347,15 @@ namespace ranges
 
   namespace __detail
   {
-    using __max_diff_type = long long;
-    using __max_size_type = unsigned long long;
-
-    template<typename _Tp>
-      concept __is_integer_like = integral<_Tp>
-       || same_as<_Tp, __max_diff_type> || same_as<_Tp, __max_size_type>;
-
-    template<typename _Tp>
-      concept __is_signed_integer_like = signed_integral<_Tp>
-       || same_as<_Tp, __max_diff_type>;
-
     template<integral _Tp>
       constexpr make_unsigned_t<_Tp>
       __to_unsigned_like(_Tp __t) noexcept
       { return __t; }
 
+    template<typename _Tp, bool _MaxDiff = same_as<_Tp, __max_diff_type>>
+      using __make_unsigned_like_t
+       = conditional_t<_MaxDiff, __max_size_type, make_unsigned_t<_Tp>>;
+
     // Part of the constraints of ranges::safe_range
     template<typename _Tp>
       concept __maybe_safe_range
index 888414a8fd6fd851b4c757e5bc6c4d9916ea6cff..ea558c76c9dbdf718e7e833f5b42831a93ad2787 100644 (file)
@@ -244,10 +244,6 @@ namespace ranges
        = !range<_Tp> && __pair_like<_Tp>
        && sentinel_for<tuple_element_t<1, _Tp>, tuple_element_t<0, _Tp>>;
 
-    template<typename _Tp, bool _MaxDiff = same_as<_Tp, __max_diff_type>>
-      using __make_unsigned_like_t
-       = conditional_t<_MaxDiff, __max_size_type, make_unsigned_t<_Tp>>;
-
   } // namespace __detail
 
   enum class subrange_kind : bool { unsized, sized };
@@ -717,7 +713,8 @@ namespace ranges
        constexpr _Iterator&
        operator+=(difference_type __n) requires __detail::__advanceable<_Winc>
        {
-         using namespace __detail;
+         using __detail::__is_integer_like;
+         using __detail::__is_signed_integer_like;
          if constexpr (__is_integer_like<_Winc>
              && !__is_signed_integer_like<_Winc>)
            {
@@ -734,7 +731,8 @@ namespace ranges
        constexpr _Iterator&
        operator-=(difference_type __n) requires __detail::__advanceable<_Winc>
        {
-         using namespace __detail;
+         using __detail::__is_integer_like;
+         using __detail::__is_signed_integer_like;
          if constexpr (__is_integer_like<_Winc>
              && !__is_signed_integer_like<_Winc>)
            {
@@ -804,7 +802,8 @@ namespace ranges
        operator-(const _Iterator& __x, const _Iterator& __y)
          requires __detail::__advanceable<_Winc>
        {
-         using namespace __detail;
+         using __detail::__is_integer_like;
+         using __detail::__is_signed_integer_like;
          using _Dt = difference_type;
          if constexpr (__is_integer_like<_Winc>)
            {
@@ -892,7 +891,8 @@ namespace ranges
       || (integral<_Winc> && integral<_Bound>)
       || sized_sentinel_for<_Bound, _Winc>
       {
-       using namespace __detail;
+       using __detail::__is_integer_like;
+       using __detail::__to_unsigned_like;
        if constexpr (__is_integer_like<_Winc> && __is_integer_like<_Bound>)
          return (_M_value < 0)
            ? ((_M_bound < 0)
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/93267.cc b/libstdc++-v3/testsuite/std/ranges/iota/93267.cc
new file mode 100644 (file)
index 0000000..39b3c77
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <ranges>
+
+void
+test01()
+{
+  // PR libstdc++/93267
+  std::ranges::iota_view<long long, int> i(0, 3);
+  static_assert( std::weakly_incrementable<decltype(i.begin())> );
+  (void) std::ranges::begin(i);
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota/iota_view.cc
new file mode 100644 (file)
index 0000000..798e745
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <ranges>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  int vals[5] = { };
+  int* out = vals;
+  for (int i : std::ranges::iota_view{1, 4})
+    *out++ = i;
+  VERIFY(out == vals + 3);
+  VERIFY(vals[0] == 1);
+  VERIFY(vals[1] == 2);
+  VERIFY(vals[2] == 3);
+  VERIFY(vals[3] == 0);
+}
+
+void
+test02()
+{
+  auto v = std::ranges::views::iota(4);
+  auto it = v.begin();
+  VERIFY( *it == 4 );
+  ++it;
+  VERIFY( *it == 5 );
+  it++;
+  VERIFY( *it == 6 );
+}
+
+void
+test03()
+{
+  auto v = std::ranges::views::iota(10, 15);
+  auto it = v.begin();
+  VERIFY( *it == 10 );
+  it += 2;
+  VERIFY( *it == 12 );
+  it += 2;
+  VERIFY( *it == 14 );
+  ++it;
+  VERIFY( it == v.end() );
+}
+
+int
+main()
+{
+  test01();
+  test02();
+  test03();
+}
diff --git a/libstdc++-v3/testsuite/std/ranges/iota_view.cc b/libstdc++-v3/testsuite/std/ranges/iota_view.cc
deleted file mode 100644 (file)
index 798e745..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2019-2020 Free Software Foundation, Inc.
-//
-// This file is part of the GNU ISO C++ Library.  This library is free
-// software; you can redistribute it and/or modify it under the
-// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 3, or (at your option)
-// any later version.
-
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING3.  If not see
-// <http://www.gnu.org/licenses/>.
-
-// { dg-options "-std=gnu++2a" }
-// { dg-do run { target c++2a } }
-
-#include <ranges>
-#include <testsuite_hooks.h>
-
-void
-test01()
-{
-  int vals[5] = { };
-  int* out = vals;
-  for (int i : std::ranges::iota_view{1, 4})
-    *out++ = i;
-  VERIFY(out == vals + 3);
-  VERIFY(vals[0] == 1);
-  VERIFY(vals[1] == 2);
-  VERIFY(vals[2] == 3);
-  VERIFY(vals[3] == 0);
-}
-
-void
-test02()
-{
-  auto v = std::ranges::views::iota(4);
-  auto it = v.begin();
-  VERIFY( *it == 4 );
-  ++it;
-  VERIFY( *it == 5 );
-  it++;
-  VERIFY( *it == 6 );
-}
-
-void
-test03()
-{
-  auto v = std::ranges::views::iota(10, 15);
-  auto it = v.begin();
-  VERIFY( *it == 10 );
-  it += 2;
-  VERIFY( *it == 12 );
-  it += 2;
-  VERIFY( *it == 14 );
-  ++it;
-  VERIFY( it == v.end() );
-}
-
-int
-main()
-{
-  test01();
-  test02();
-  test03();
-}