public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
@ 2024-04-17 18:24 Michael Levine (BLOOMBERG/ 919 3RD A)
  2024-04-18 21:58 ` Patrick Palka
  2024-05-17 16:59 ` [PATCH v2] libstdc++: Fix std::ranges::iota " Michael Levine (BLOOMBERG/ 731 LEX)
  0 siblings, 2 replies; 13+ messages in thread
From: Michael Levine (BLOOMBERG/ 919 3RD A) @ 2024-04-17 18:24 UTC (permalink / raw)
  To: libstdc++, gcc-patches


[-- Attachment #1.1: Type: text/plain, Size: 750 bytes --]

This patch fixes GCC Bug 108760:  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760

Before this patch, using std::ranges::iota required including <algorithm> when it should have been sufficient to only include <numeric>.

When the patch is applied, the following code will compile:  https://godbolt.org/z/33EPeqd1b

I added a test case for this change as well.

I built my local version of gcc using the following configuration:  $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto

and I tested my changes by running:  $ make check-c++ -jN -k

I ran this on the following OS:

Virtualization: wsl
Operating System: Ubuntu 20.04.6 LTS
Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
Architecture: x86-64



[-- Attachment #2: 108760.patch --]
[-- Type: application/octet-stream, Size: 6656 bytes --]

From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Fri, 23 Feb 2024 14:13:13 -0500
Subject: [PATCH 1/2] Fix the bug

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algo.h | 52 ----------------------
 libstdc++-v3/include/bits/stl_numeric.h | 57 ++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 53 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 62faff173bd..d258be0b93f 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3521,58 +3521,6 @@ namespace ranges
 
 #endif // __glibcxx_ranges_contains
 
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-  template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
-
-  struct __iota_fn
-  {
-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
-      requires indirectly_writable<_Out, const _Tp&>
-      constexpr iota_result<_Out, _Tp>
-      operator()(_Out __first, _Sent __last, _Tp __value) const
-      {
-	while (__first != __last)
-	  {
-	    *__first = static_cast<const _Tp&>(__value);
-	    ++__first;
-	    ++__value;
-	  }
-	return {std::move(__first), std::move(__value)};
-      }
-
-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
-      operator()(_Range&& __r, _Tp __value) const
-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
-  };
-
-  inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
-
 #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
 
   struct __find_last_fn
diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
index fe911154ab7..1b06c26dc02 100644
--- a/libstdc++-v3/include/bits/stl_numeric.h
+++ b/libstdc++-v3/include/bits/stl_numeric.h
@@ -59,7 +59,7 @@
 #include <bits/concept_check.h>
 #include <debug/debug.h>
 #include <bits/move.h> // For _GLIBCXX_MOVE
-
+#include <bits/ranges_base.h> // For _Range as used by std::ranges::iota
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 #endif
 
+namespace ranges
+{
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+  template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+      [[no_unique_address]] _Out out;
+      [[no_unique_address]] _Tp value;
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+	  && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+	  && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+
+  template<typename _Out, typename _Tp>
+    using iota_result = out_value_result<_Out, _Tp>;
+
+  struct __iota_fn
+  {
+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
+      requires indirectly_writable<_Out, const _Tp&>
+      constexpr iota_result<_Out, _Tp>
+      operator()(_Out __first, _Sent __last, _Tp __value) const
+      {
+	while (__first != __last)
+	  {
+	    *__first = static_cast<const _Tp&>(__value);
+	    ++__first;
+	    ++__value;
+	  }
+	return {std::move(__first), std::move(__value)};
+      }
+
+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
+      operator()(_Range&& __r, _Tp __value) const
+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
+  };
+
+  inline constexpr __iota_fn iota{};
+
+#endif // __glibcxx_ranges_iota
+}
+
 _GLIBCXX_END_NAMESPACE_VERSION
 
 _GLIBCXX_BEGIN_NAMESPACE_ALGO
-- 
2.25.1


From c52c8d79fb3c7dc9d2512d1635712ffcd3dea07c Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Tue, 16 Apr 2024 16:45:37 -0400
Subject: [PATCH 2/2] Added a test to verify that the bug has been fixed

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 .../testsuite/std/ranges/iota/108760.cc       | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/iota/108760.cc

diff --git a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
new file mode 100644
index 00000000000..4f71383687c
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2020-2024 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/>.
+
+// Fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
+// { dg-do run { target c++23 } }
+
+#include <numeric>
+#include <testsuite_hooks.h>
+
+const int ARR_SIZE = 4;
+
+void
+test01()
+{
+    int expected_arr[ARR_SIZE] = {0, 1, 2, 3};
+    int input_arr[ARR_SIZE] = {0, 0, 0, 0};
+    std::ranges::iota(input_arr, 0);
+    for (int i = 0; i < ARR_SIZE; i++) {
+        VERIFY( input_arr[i] == expected_arr[i]);
+    }
+}
+
+int
+main()
+{
+    test01();
+}
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
  2024-04-17 18:24 [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760] Michael Levine (BLOOMBERG/ 919 3RD A)
@ 2024-04-18 21:58 ` Patrick Palka
  2024-04-19  9:18   ` Jonathan Wakely
  2024-05-17 16:59 ` [PATCH v2] libstdc++: Fix std::ranges::iota " Michael Levine (BLOOMBERG/ 731 LEX)
  1 sibling, 1 reply; 13+ messages in thread
From: Patrick Palka @ 2024-04-18 21:58 UTC (permalink / raw)
  To: Michael Levine (BLOOMBERG/ 919 3RD A); +Cc: libstdc++, gcc-patches

On Wed, 17 Apr 2024, Michael Levine (BLOOMBERG/ 919 3RD A) wrote:

> This patch fixes GCC Bug 108760: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including <algorithm> when it should have been sufficient to only include <numeric>.
> 
> When the patch is applied, the following code will compile: https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k

Nice, thanks for the patch!

> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64

> From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
> From: Michael Levine <mlevine55@bloomberg.net>
> Date: Fri, 23 Feb 2024 14:13:13 -0500
> Subject: [PATCH 1/2] Fix the bug
> 
> Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
> ---
>  libstdc++-v3/include/bits/ranges_algo.h | 52 ----------------------
>  libstdc++-v3/include/bits/stl_numeric.h | 57 ++++++++++++++++++++++++-
>  2 files changed, 56 insertions(+), 53 deletions(-)
> 
> diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
> index 62faff173bd..d258be0b93f 100644
> --- a/libstdc++-v3/include/bits/ranges_algo.h
> +++ b/libstdc++-v3/include/bits/ranges_algo.h
> @@ -3521,58 +3521,6 @@ namespace ranges
>  
>  #endif // __glibcxx_ranges_contains
>  
> -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> -
> -  template<typename _Out, typename _Tp>
> -    struct out_value_result
> -    {
> -      [[no_unique_address]] _Out out;
> -      [[no_unique_address]] _Tp value;
> -
> -      template<typename _Out2, typename _Tp2>
> -	requires convertible_to<const _Out&, _Out2>
> -	  && convertible_to<const _Tp&, _Tp2>
> -	constexpr
> -	operator out_value_result<_Out2, _Tp2>() const &
> -	{ return {out, value}; }
> -
> -      template<typename _Out2, typename _Tp2>
> -	requires convertible_to<_Out, _Out2>
> -	  && convertible_to<_Tp, _Tp2>
> -	constexpr
> -	operator out_value_result<_Out2, _Tp2>() &&
> -	{ return {std::move(out), std::move(value)}; }
> -    };
> -
> -  template<typename _Out, typename _Tp>
> -    using iota_result = out_value_result<_Out, _Tp>;
> -
> -  struct __iota_fn
> -  {
> -    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
> -      requires indirectly_writable<_Out, const _Tp&>
> -      constexpr iota_result<_Out, _Tp>
> -      operator()(_Out __first, _Sent __last, _Tp __value) const
> -      {
> -	while (__first != __last)
> -	  {
> -	    *__first = static_cast<const _Tp&>(__value);
> -	    ++__first;
> -	    ++__value;
> -	  }
> -	return {std::move(__first), std::move(__value)};
> -      }
> -
> -    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> -      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> -      operator()(_Range&& __r, _Tp __value) const
> -      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
> -  };
> -
> -  inline constexpr __iota_fn iota{};
> -
> -#endif // __glibcxx_ranges_iota
> -
>  #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
>  
>    struct __find_last_fn
> diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
> index fe911154ab7..1b06c26dc02 100644
> --- a/libstdc++-v3/include/bits/stl_numeric.h
> +++ b/libstdc++-v3/include/bits/stl_numeric.h
> @@ -59,7 +59,7 @@
>  #include <bits/concept_check.h>
>  #include <debug/debug.h>
>  #include <bits/move.h> // For _GLIBCXX_MOVE
> -
> +#include <bits/ranges_base.h> // For _Range as used by std::ranges::iota
>  
>  namespace std _GLIBCXX_VISIBILITY(default)
>  {
> @@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>      }
>  #endif
>  
> +namespace ranges
> +{
> +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> +
> +  template<typename _Out, typename _Tp>
> +    struct out_value_result
> +    {
> +      [[no_unique_address]] _Out out;
> +      [[no_unique_address]] _Tp value;
> +
> +      template<typename _Out2, typename _Tp2>
> +	requires convertible_to<const _Out&, _Out2>
> +	  && convertible_to<const _Tp&, _Tp2>
> +	constexpr
> +	operator out_value_result<_Out2, _Tp2>() const &
> +	{ return {out, value}; }
> +
> +      template<typename _Out2, typename _Tp2>
> +	requires convertible_to<_Out, _Out2>
> +	  && convertible_to<_Tp, _Tp2>
> +	constexpr
> +	operator out_value_result<_Out2, _Tp2>() &&
> +	{ return {std::move(out), std::move(value)}; }
> +    };

IIUC out_value_result should continue to be available from <algorithm>, so we
probably don't want to move it to <numeric> (or one of its internal headers).
Better would be to move it to <bits/ranges_algobase.h> I think.

> +
> +  template<typename _Out, typename _Tp>
> +    using iota_result = out_value_result<_Out, _Tp>;
> +
> +  struct __iota_fn
> +  {
> +    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
> +      requires indirectly_writable<_Out, const _Tp&>
> +      constexpr iota_result<_Out, _Tp>
> +      operator()(_Out __first, _Sent __last, _Tp __value) const
> +      {
> +	while (__first != __last)
> +	  {
> +	    *__first = static_cast<const _Tp&>(__value);
> +	    ++__first;
> +	    ++__value;
> +	  }
> +	return {std::move(__first), std::move(__value)};
> +      }
> +
> +    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> +      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> +      operator()(_Range&& __r, _Tp __value) const
> +      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
> +  };
> +
> +  inline constexpr __iota_fn iota{};
> +
> +#endif // __glibcxx_ranges_iota

And it might be cleaner to move ranges::iota directly into <numeric>
instead (and then include <bits/ranges_algobase.h> directly from <numeric>
to bring in <bits/ranges_base.h> and out_value_result) since
<bits/stl_numeric.h> has other users besides <numeric> which would
otherwise get unnecessarily bloated.

> +}
> +
>  _GLIBCXX_END_NAMESPACE_VERSION
>  
>  _GLIBCXX_BEGIN_NAMESPACE_ALGO
> -- 
> 2.25.1
> 
> 
> From c52c8d79fb3c7dc9d2512d1635712ffcd3dea07c Mon Sep 17 00:00:00 2001
> From: Michael Levine <mlevine55@bloomberg.net>
> Date: Tue, 16 Apr 2024 16:45:37 -0400
> Subject: [PATCH 2/2] Added a test to verify that the bug has been fixed
> 
> Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
> ---
>  .../testsuite/std/ranges/iota/108760.cc       | 41 +++++++++++++++++++
>  1 file changed, 41 insertions(+)
>  create mode 100644 libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> 
> diff --git a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> new file mode 100644
> index 00000000000..4f71383687c
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> @@ -0,0 +1,41 @@
> +// Copyright (C) 2020-2024 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/>.
> +
> +// Fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> +// { dg-do run { target c++23 } }
> +
> +#include <numeric>
> +#include <testsuite_hooks.h>
> +
> +const int ARR_SIZE = 4;
> +
> +void
> +test01()
> +{
> +    int expected_arr[ARR_SIZE] = {0, 1, 2, 3};
> +    int input_arr[ARR_SIZE] = {0, 0, 0, 0};
> +    std::ranges::iota(input_arr, 0);
> +    for (int i = 0; i < ARR_SIZE; i++) {
> +        VERIFY( input_arr[i] == expected_arr[i]);
> +    }
> +}
> +
> +int
> +main()
> +{
> +    test01();
> +}

Instead of adding a new test, perhaps we should just move the
existing test libstdc++-v3/testsuite/25_algorithms/iota/1.cc
to libstdc++-v3/testsuite/26_numerics/iota/1.cc and change it
to include <numeric> instead of <algorithm>?

> -- 
> 2.25.1
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
  2024-04-18 21:58 ` Patrick Palka
@ 2024-04-19  9:18   ` Jonathan Wakely
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2024-04-19  9:18 UTC (permalink / raw)
  To: Patrick Palka
  Cc: Michael Levine (BLOOMBERG/ 919 3RD A), libstdc++, gcc-patches

On Thu, 18 Apr 2024 at 22:59, Patrick Palka <ppalka@redhat.com> wrote:
>
> On Wed, 17 Apr 2024, Michael Levine (BLOOMBERG/ 919 3RD A) wrote:
>
> > This patch fixes GCC Bug 108760: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> > Before this patch, using std::ranges::iota required including <algorithm> when it should have been sufficient to only include <numeric>.
> >
> > When the patch is applied, the following code will compile: https://godbolt.org/z/33EPeqd1b
> >
> > I added a test case for this change as well.
> >
> > I built my local version of gcc using the following configuration: $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto
> >
> > and I tested my changes by running: $ make check-c++ -jN -k
>
> Nice, thanks for the patch!
>
> >
> > I ran this on the following OS:
> >
> > Virtualization: wsl
> > Operating System: Ubuntu 20.04.6 LTS
> > Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> > Architecture: x86-64
>
> > From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
> > From: Michael Levine <mlevine55@bloomberg.net>
> > Date: Fri, 23 Feb 2024 14:13:13 -0500
> > Subject: [PATCH 1/2] Fix the bug
> >
> > Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
> > ---
> >  libstdc++-v3/include/bits/ranges_algo.h | 52 ----------------------
> >  libstdc++-v3/include/bits/stl_numeric.h | 57 ++++++++++++++++++++++++-
> >  2 files changed, 56 insertions(+), 53 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
> > index 62faff173bd..d258be0b93f 100644
> > --- a/libstdc++-v3/include/bits/ranges_algo.h
> > +++ b/libstdc++-v3/include/bits/ranges_algo.h
> > @@ -3521,58 +3521,6 @@ namespace ranges
> >
> >  #endif // __glibcxx_ranges_contains
> >
> > -#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> > -
> > -  template<typename _Out, typename _Tp>
> > -    struct out_value_result
> > -    {
> > -      [[no_unique_address]] _Out out;
> > -      [[no_unique_address]] _Tp value;
> > -
> > -      template<typename _Out2, typename _Tp2>
> > -     requires convertible_to<const _Out&, _Out2>
> > -       && convertible_to<const _Tp&, _Tp2>
> > -     constexpr
> > -     operator out_value_result<_Out2, _Tp2>() const &
> > -     { return {out, value}; }
> > -
> > -      template<typename _Out2, typename _Tp2>
> > -     requires convertible_to<_Out, _Out2>
> > -       && convertible_to<_Tp, _Tp2>
> > -     constexpr
> > -     operator out_value_result<_Out2, _Tp2>() &&
> > -     { return {std::move(out), std::move(value)}; }
> > -    };
> > -
> > -  template<typename _Out, typename _Tp>
> > -    using iota_result = out_value_result<_Out, _Tp>;
> > -
> > -  struct __iota_fn
> > -  {
> > -    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
> > -      requires indirectly_writable<_Out, const _Tp&>
> > -      constexpr iota_result<_Out, _Tp>
> > -      operator()(_Out __first, _Sent __last, _Tp __value) const
> > -      {
> > -     while (__first != __last)
> > -       {
> > -         *__first = static_cast<const _Tp&>(__value);
> > -         ++__first;
> > -         ++__value;
> > -       }
> > -     return {std::move(__first), std::move(__value)};
> > -      }
> > -
> > -    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> > -      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> > -      operator()(_Range&& __r, _Tp __value) const
> > -      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
> > -  };
> > -
> > -  inline constexpr __iota_fn iota{};
> > -
> > -#endif // __glibcxx_ranges_iota
> > -
> >  #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
> >
> >    struct __find_last_fn
> > diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
> > index fe911154ab7..1b06c26dc02 100644
> > --- a/libstdc++-v3/include/bits/stl_numeric.h
> > +++ b/libstdc++-v3/include/bits/stl_numeric.h
> > @@ -59,7 +59,7 @@
> >  #include <bits/concept_check.h>
> >  #include <debug/debug.h>
> >  #include <bits/move.h> // For _GLIBCXX_MOVE
> > -
> > +#include <bits/ranges_base.h> // For _Range as used by std::ranges::iota
> >
> >  namespace std _GLIBCXX_VISIBILITY(default)
> >  {
> > @@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >      }
> >  #endif
> >
> > +namespace ranges
> > +{
> > +#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> > +
> > +  template<typename _Out, typename _Tp>
> > +    struct out_value_result
> > +    {
> > +      [[no_unique_address]] _Out out;
> > +      [[no_unique_address]] _Tp value;
> > +
> > +      template<typename _Out2, typename _Tp2>
> > +     requires convertible_to<const _Out&, _Out2>
> > +       && convertible_to<const _Tp&, _Tp2>
> > +     constexpr
> > +     operator out_value_result<_Out2, _Tp2>() const &
> > +     { return {out, value}; }
> > +
> > +      template<typename _Out2, typename _Tp2>
> > +     requires convertible_to<_Out, _Out2>
> > +       && convertible_to<_Tp, _Tp2>
> > +     constexpr
> > +     operator out_value_result<_Out2, _Tp2>() &&
> > +     { return {std::move(out), std::move(value)}; }
> > +    };
>
> IIUC out_value_result should continue to be available from <algorithm>, so we
> probably don't want to move it to <numeric> (or one of its internal headers).
> Better would be to move it to <bits/ranges_algobase.h> I think.
>
> > +
> > +  template<typename _Out, typename _Tp>
> > +    using iota_result = out_value_result<_Out, _Tp>;
> > +
> > +  struct __iota_fn
> > +  {
> > +    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
> > +      requires indirectly_writable<_Out, const _Tp&>
> > +      constexpr iota_result<_Out, _Tp>
> > +      operator()(_Out __first, _Sent __last, _Tp __value) const
> > +      {
> > +     while (__first != __last)
> > +       {
> > +         *__first = static_cast<const _Tp&>(__value);
> > +         ++__first;
> > +         ++__value;
> > +       }
> > +     return {std::move(__first), std::move(__value)};
> > +      }
> > +
> > +    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> > +      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> > +      operator()(_Range&& __r, _Tp __value) const
> > +      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
> > +  };
> > +
> > +  inline constexpr __iota_fn iota{};
> > +
> > +#endif // __glibcxx_ranges_iota
>
> And it might be cleaner to move ranges::iota directly into <numeric>
> instead (and then include <bits/ranges_algobase.h> directly from <numeric>
> to bring in <bits/ranges_base.h> and out_value_result) since
> <bits/stl_numeric.h> has other users besides <numeric> which would
> otherwise get unnecessarily bloated.

Good idea, thanks, Patrick.

> > +}
> > +
> >  _GLIBCXX_END_NAMESPACE_VERSION
> >
> >  _GLIBCXX_BEGIN_NAMESPACE_ALGO
> > --
> > 2.25.1
> >
> >
> > From c52c8d79fb3c7dc9d2512d1635712ffcd3dea07c Mon Sep 17 00:00:00 2001
> > From: Michael Levine <mlevine55@bloomberg.net>
> > Date: Tue, 16 Apr 2024 16:45:37 -0400
> > Subject: [PATCH 2/2] Added a test to verify that the bug has been fixed
> >
> > Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
> > ---
> >  .../testsuite/std/ranges/iota/108760.cc       | 41 +++++++++++++++++++
> >  1 file changed, 41 insertions(+)
> >  create mode 100644 libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> >
> > diff --git a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> > new file mode 100644
> > index 00000000000..4f71383687c
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
> > @@ -0,0 +1,41 @@
> > +// Copyright (C) 2020-2024 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/>.
> > +
> > +// Fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> > +// { dg-do run { target c++23 } }
> > +
> > +#include <numeric>
> > +#include <testsuite_hooks.h>
> > +
> > +const int ARR_SIZE = 4;
> > +
> > +void
> > +test01()
> > +{
> > +    int expected_arr[ARR_SIZE] = {0, 1, 2, 3};
> > +    int input_arr[ARR_SIZE] = {0, 0, 0, 0};
> > +    std::ranges::iota(input_arr, 0);
> > +    for (int i = 0; i < ARR_SIZE; i++) {
> > +        VERIFY( input_arr[i] == expected_arr[i]);
> > +    }
> > +}
> > +
> > +int
> > +main()
> > +{
> > +    test01();
> > +}
>
> Instead of adding a new test, perhaps we should just move the
> existing test libstdc++-v3/testsuite/25_algorithms/iota/1.cc
> to libstdc++-v3/testsuite/26_numerics/iota/1.cc and change it
> to include <numeric> instead of <algorithm>?


Yes please, the existing test is better as it uses an output range
instead of a contiguous range for the result. And the new test has
incorrect copyright/licence info. As a new test, it should not have
2020-2024 as the copyright date, and it should not be copyright FSF
unless Michael (or Bloomberg) has a copyright assignment on file to
assign copyright to the FSF. Since Michael added a DCO Signed-off-by:
tag, I assume this is being contributed under the
https://gcc.gnu.org/dco.html terms, not under copyright assignment, so
the test should not be copyright FSF at all.

I don't bother adding copyright and license info to trivial tests like
this, it's not doing anything meaningful and so I don't consider it
copyrightable. There's no novel implementation or non-trivial logic in
this test code, it's literally just exercising an API for the purpose
of testing it. There is not really any other way to do that, so there
is no "originality" in that work.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]
  2024-04-17 18:24 [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760] Michael Levine (BLOOMBERG/ 919 3RD A)
  2024-04-18 21:58 ` Patrick Palka
@ 2024-05-17 16:59 ` Michael Levine (BLOOMBERG/ 731 LEX)
  2024-05-23 22:41   ` Patrick Palka
  1 sibling, 1 reply; 13+ messages in thread
From: Michael Levine (BLOOMBERG/ 731 LEX) @ 2024-05-17 16:59 UTC (permalink / raw)
  To: gcc-patches, libstdc++


[-- Attachment #1.1: Type: text/plain, Size: 1929 bytes --]

This is the revised version of my patch incorporating the provided feedback from Patrick Palka and Jonathan Wakely.

This patch fixes GCC Bug 108760: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760

I moved out_value_result to <bits/ranges_algobase.h>, moved std::ranges:iota into <numeric>, removed my new test, and moved and renamed the existing test.

I built my local version of gcc using the following configuration:  $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto
I then ran $ make -jN 
and $ make -jN install

Using the locally installed version, the following code compiled:  https://godbolt.org/z/33EPeqd1b

I tested my changes by running:  $ make check-c++ -jN -k
I personally found it difficult to understand the results of running the tests.

I ran this on the following OS:

Virtualization: wsl
Operating System: Ubuntu 20.04.6 LTS
Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
Architecture: x86-64


From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00To:  libstdc++@gcc.gnu.org,  gcc-patches@gcc.gnu.org
Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
This patch fixes GCC Bug 108760:  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760

Before this patch, using std::ranges::iota required including <algorithm> when it should have been sufficient to only include <numeric>.

When the patch is applied, the following code will compile:  https://godbolt.org/z/33EPeqd1b

I added a test case for this change as well.

I built my local version of gcc using the following configuration:  $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto

and I tested my changes by running:  $ make check-c++ -jN -k

I ran this on the following OS:

Virtualization: wsl
Operating System: Ubuntu 20.04.6 LTS
Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
Architecture: x86-64



[-- Attachment #2: 108760v2.patch --]
[-- Type: application/octet-stream, Size: 25249 bytes --]

From bd04070c281572ed7a3b48e3d33543e25b8c8afe Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Fri, 23 Feb 2024 14:13:13 -0500
Subject: [PATCH 01/11] Fix the bug

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algo.h | 52 ----------------------
 libstdc++-v3/include/bits/stl_numeric.h | 57 ++++++++++++++++++++++++-
 2 files changed, 56 insertions(+), 53 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 62faff173bd..d258be0b93f 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3521,58 +3521,6 @@ namespace ranges
 
 #endif // __glibcxx_ranges_contains
 
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-  template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
-
-  struct __iota_fn
-  {
-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
-      requires indirectly_writable<_Out, const _Tp&>
-      constexpr iota_result<_Out, _Tp>
-      operator()(_Out __first, _Sent __last, _Tp __value) const
-      {
-	while (__first != __last)
-	  {
-	    *__first = static_cast<const _Tp&>(__value);
-	    ++__first;
-	    ++__value;
-	  }
-	return {std::move(__first), std::move(__value)};
-      }
-
-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
-      operator()(_Range&& __r, _Tp __value) const
-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
-  };
-
-  inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
-
 #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
 
   struct __find_last_fn
diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
index fe911154ab7..1b06c26dc02 100644
--- a/libstdc++-v3/include/bits/stl_numeric.h
+++ b/libstdc++-v3/include/bits/stl_numeric.h
@@ -59,7 +59,7 @@
 #include <bits/concept_check.h>
 #include <debug/debug.h>
 #include <bits/move.h> // For _GLIBCXX_MOVE
-
+#include <bits/ranges_base.h> // For _Range as used by std::ranges::iota
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -102,6 +102,61 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 #endif
 
+namespace ranges
+{
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+  template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+      [[no_unique_address]] _Out out;
+      [[no_unique_address]] _Tp value;
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+	  && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+	  && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+
+  template<typename _Out, typename _Tp>
+    using iota_result = out_value_result<_Out, _Tp>;
+
+  struct __iota_fn
+  {
+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
+      requires indirectly_writable<_Out, const _Tp&>
+      constexpr iota_result<_Out, _Tp>
+      operator()(_Out __first, _Sent __last, _Tp __value) const
+      {
+	while (__first != __last)
+	  {
+	    *__first = static_cast<const _Tp&>(__value);
+	    ++__first;
+	    ++__value;
+	  }
+	return {std::move(__first), std::move(__value)};
+      }
+
+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
+      operator()(_Range&& __r, _Tp __value) const
+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
+  };
+
+  inline constexpr __iota_fn iota{};
+
+#endif // __glibcxx_ranges_iota
+}
+
 _GLIBCXX_END_NAMESPACE_VERSION
 
 _GLIBCXX_BEGIN_NAMESPACE_ALGO
-- 
2.25.1


From c52c8d79fb3c7dc9d2512d1635712ffcd3dea07c Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Tue, 16 Apr 2024 16:45:37 -0400
Subject: [PATCH 02/11] Added a test to verify that the bug has been fixed

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 .../testsuite/std/ranges/iota/108760.cc       | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/iota/108760.cc

diff --git a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
new file mode 100644
index 00000000000..4f71383687c
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
@@ -0,0 +1,41 @@
+// Copyright (C) 2020-2024 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/>.
+
+// Fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
+// { dg-do run { target c++23 } }
+
+#include <numeric>
+#include <testsuite_hooks.h>
+
+const int ARR_SIZE = 4;
+
+void
+test01()
+{
+    int expected_arr[ARR_SIZE] = {0, 1, 2, 3};
+    int input_arr[ARR_SIZE] = {0, 0, 0, 0};
+    std::ranges::iota(input_arr, 0);
+    for (int i = 0; i < ARR_SIZE; i++) {
+        VERIFY( input_arr[i] == expected_arr[i]);
+    }
+}
+
+int
+main()
+{
+    test01();
+}
-- 
2.25.1


From c6a10df5515651fa0bafcae6e1ed63c2aeacf64c Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Wed, 8 May 2024 09:24:51 -0400
Subject: [PATCH 03/11] Moved the ranges namespaced code into numeric itself as
 per PR feedback

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/stl_numeric.h | 55 -------------------------
 libstdc++-v3/include/std/numeric        | 55 +++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
index 1b06c26dc02..88a4e24ee64 100644
--- a/libstdc++-v3/include/bits/stl_numeric.h
+++ b/libstdc++-v3/include/bits/stl_numeric.h
@@ -102,61 +102,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     }
 #endif
 
-namespace ranges
-{
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-  template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
-
-  struct __iota_fn
-  {
-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
-      requires indirectly_writable<_Out, const _Tp&>
-      constexpr iota_result<_Out, _Tp>
-      operator()(_Out __first, _Sent __last, _Tp __value) const
-      {
-	while (__first != __last)
-	  {
-	    *__first = static_cast<const _Tp&>(__value);
-	    ++__first;
-	    ++__value;
-	  }
-	return {std::move(__first), std::move(__value)};
-      }
-
-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
-      operator()(_Range&& __r, _Tp __value) const
-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
-  };
-
-  inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
-}
-
 _GLIBCXX_END_NAMESPACE_VERSION
 
 _GLIBCXX_BEGIN_NAMESPACE_ALGO
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index c912db4a519..7ac77fda0bb 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -726,6 +726,61 @@ namespace __detail
   /// @} group numeric_ops
 #endif // C++17
 
+namespace ranges
+{
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+  template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+      [[no_unique_address]] _Out out;
+      [[no_unique_address]] _Tp value;
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+	  && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+	  && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+
+  template<typename _Out, typename _Tp>
+    using iota_result = out_value_result<_Out, _Tp>;
+
+  struct __iota_fn
+  {
+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
+      requires indirectly_writable<_Out, const _Tp&>
+      constexpr iota_result<_Out, _Tp>
+      operator()(_Out __first, _Sent __last, _Tp __value) const
+      {
+	while (__first != __last)
+	  {
+	    *__first = static_cast<const _Tp&>(__value);
+	    ++__first;
+	    ++__value;
+	  }
+	return {std::move(__first), std::move(__value)};
+      }
+
+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
+      operator()(_Range&& __r, _Tp __value) const
+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
+  };
+
+  inline constexpr __iota_fn iota{};
+
+#endif // __glibcxx_ranges_iota
+}
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
-- 
2.25.1


From 59d72fca69b8e74974bdf2466173467567e08869 Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Wed, 8 May 2024 11:57:44 -0400
Subject: [PATCH 04/11] Moved more code around

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algobase.h | 26 +++++++++++++++++++++
 libstdc++-v3/include/bits/stl_numeric.h     |  1 -
 libstdc++-v3/include/std/numeric            |  7 +++++-
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index e26a73a27d6..3b6de54db78 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -43,6 +43,32 @@
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+    template<typename _Out, typename _Tp>
+    struct out_value_result
+{
+    [[no_unique_address]] _Out out;
+    [[no_unique_address]] _Tp value;
+
+    template<typename _Out2, typename _Tp2>
+    requires convertible_to<const _Out&, _Out2>
+    && convertible_to<const _Tp&, _Tp2>
+    constexpr
+    operator out_value_result<_Out2, _Tp2>() const &
+    { return {out, value}; }
+
+    template<typename _Out2, typename _Tp2>
+    requires convertible_to<_Out, _Out2>
+    && convertible_to<_Tp, _Tp2>
+    constexpr
+    operator out_value_result<_Out2, _Tp2>() &&
+    { return {std::move(out), std::move(value)}; }
+};
+
+#endif // __glibcxx_ranges_iota
+
 namespace ranges
 {
   namespace __detail
diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
index 88a4e24ee64..302515428d6 100644
--- a/libstdc++-v3/include/bits/stl_numeric.h
+++ b/libstdc++-v3/include/bits/stl_numeric.h
@@ -59,7 +59,6 @@
 #include <bits/concept_check.h>
 #include <debug/debug.h>
 #include <bits/move.h> // For _GLIBCXX_MOVE
-#include <bits/ranges_base.h> // For _Range as used by std::ranges::iota
 
 namespace std _GLIBCXX_VISIBILITY(default)
 {
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 7ac77fda0bb..c97c2a1ba70 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -65,6 +65,11 @@
 # include <parallel/numeric>
 #endif
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+#include <bits/ranges_base.h> // for _Range as used by std::ranges::iota
+#include <bits/ranges_algobase.h> // for std::out_value_result as used by std::ranges::iota
+#endif // __glibcxx_ranges_iota
+
 #if __cplusplus >= 201402L
 # include <type_traits>
 # include <bit>
@@ -779,7 +784,7 @@ namespace ranges
   inline constexpr __iota_fn iota{};
 
 #endif // __glibcxx_ranges_iota
-}
+} // namespace ranges
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
-- 
2.25.1


From 134c3546f921257855edbbf8a1e42f3d66b5f676 Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Wed, 8 May 2024 11:59:42 -0400
Subject: [PATCH 05/11] Removed the new, unnecessary test

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 .../testsuite/std/ranges/iota/108760.cc       | 41 -------------------
 1 file changed, 41 deletions(-)
 delete mode 100644 libstdc++-v3/testsuite/std/ranges/iota/108760.cc

diff --git a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc b/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
deleted file mode 100644
index 4f71383687c..00000000000
--- a/libstdc++-v3/testsuite/std/ranges/iota/108760.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2020-2024 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/>.
-
-// Fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
-// { dg-do run { target c++23 } }
-
-#include <numeric>
-#include <testsuite_hooks.h>
-
-const int ARR_SIZE = 4;
-
-void
-test01()
-{
-    int expected_arr[ARR_SIZE] = {0, 1, 2, 3};
-    int input_arr[ARR_SIZE] = {0, 0, 0, 0};
-    std::ranges::iota(input_arr, 0);
-    for (int i = 0; i < ARR_SIZE; i++) {
-        VERIFY( input_arr[i] == expected_arr[i]);
-    }
-}
-
-int
-main()
-{
-    test01();
-}
-- 
2.25.1


From 947222aad5f1b5bd69e25bc28e1a9e07a522c2b5 Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Wed, 8 May 2024 12:08:29 -0400
Subject: [PATCH 06/11] removed the new test and renamed and updated the
 existing test

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 .../{25_algorithms/iota/1.cc => 26_numerics/iota/2.cc}          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 rename libstdc++-v3/testsuite/{25_algorithms/iota/1.cc => 26_numerics/iota/2.cc} (96%)

diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
similarity index 96%
rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
index 61bf418b4da..040c48d91ce 100644
--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
@@ -1,6 +1,6 @@
 // { dg-do run { target c++23 } }
 
-#include <algorithm>
+#include <numeric>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
-- 
2.25.1


From d7a8cf3fd0812ac6e1ba56b65424f37a18ac7ace Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Thu, 9 May 2024 10:05:54 -0400
Subject: [PATCH 07/11] Fix build issues and extra copy of imported code

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algobase.h | 26 +--------------------
 libstdc++-v3/include/std/numeric            | 26 ++-------------------
 2 files changed, 3 insertions(+), 49 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 3b6de54db78..6a31aca163d 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -35,6 +35,7 @@
 #include <compare>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_iterator.h>
+#include <bits/stl_algobase.h> // __memcpy
 #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
 #include <bits/invoke.h>      // __invoke
 #include <bits/cpp_type_traits.h> // __is_byte
@@ -44,31 +45,6 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-    template<typename _Out, typename _Tp>
-    struct out_value_result
-{
-    [[no_unique_address]] _Out out;
-    [[no_unique_address]] _Tp value;
-
-    template<typename _Out2, typename _Tp2>
-    requires convertible_to<const _Out&, _Out2>
-    && convertible_to<const _Tp&, _Tp2>
-    constexpr
-    operator out_value_result<_Out2, _Tp2>() const &
-    { return {out, value}; }
-
-    template<typename _Out2, typename _Tp2>
-    requires convertible_to<_Out, _Out2>
-    && convertible_to<_Tp, _Tp2>
-    constexpr
-    operator out_value_result<_Out2, _Tp2>() &&
-    { return {std::move(out), std::move(value)}; }
-};
-
-#endif // __glibcxx_ranges_iota
-
 namespace ranges
 {
   namespace __detail
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index c97c2a1ba70..3a48070210c 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -66,8 +66,7 @@
 #endif
 
 #if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-#include <bits/ranges_base.h> // for _Range as used by std::ranges::iota
-#include <bits/ranges_algobase.h> // for std::out_value_result as used by std::ranges::iota
+#include <bits/ranges_algobase.h> // for std::out_value_result as used by std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from which _Range is used by std::ranges::iota
 #endif // __glibcxx_ranges_iota
 
 #if __cplusplus >= 201402L
@@ -736,28 +735,7 @@ namespace ranges
 #if __glibcxx_ranges_iota >= 202202L // C++ >= 23
 
   template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
+  using iota_result = std::out_value_result<_Out, _Tp>;
 
   struct __iota_fn
   {
-- 
2.25.1


From 8b16de1fa8dfd61fe9fe3669d61edfb71c25cbe4 Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Thu, 9 May 2024 10:09:36 -0400
Subject: [PATCH 08/11] Fix spacing changes

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algobase.h | 1 -
 libstdc++-v3/include/bits/stl_numeric.h     | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index 6a31aca163d..c3d873a10c9 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -44,7 +44,6 @@
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
-
 namespace ranges
 {
   namespace __detail
diff --git a/libstdc++-v3/include/bits/stl_numeric.h b/libstdc++-v3/include/bits/stl_numeric.h
index 302515428d6..fe911154ab7 100644
--- a/libstdc++-v3/include/bits/stl_numeric.h
+++ b/libstdc++-v3/include/bits/stl_numeric.h
@@ -60,6 +60,7 @@
 #include <debug/debug.h>
 #include <bits/move.h> // For _GLIBCXX_MOVE
 
+
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
-- 
2.25.1


From 9ddb15a35f36ea041bb7480747fe3170b9cc9eab Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Thu, 16 May 2024 14:55:57 -0400
Subject: [PATCH 09/11] Removed the std qualifier from the template

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/std/numeric | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 3a48070210c..3a4917b89f5 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -735,7 +735,7 @@ namespace ranges
 #if __glibcxx_ranges_iota >= 202202L // C++ >= 23
 
   template<typename _Out, typename _Tp>
-  using iota_result = std::out_value_result<_Out, _Tp>;
+  using iota_result = out_value_result<_Out, _Tp>;
 
   struct __iota_fn
   {
-- 
2.25.1


From 8b254e95fc9308ae931ec5eae8739d724b5c2ff3 Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Thu, 16 May 2024 16:05:00 -0400
Subject: [PATCH 10/11] Added the missing out_value_result

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algobase.h | 26 +++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index c3d873a10c9..965b36aed35 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -71,6 +71,32 @@ namespace ranges
 	__is_move_iterator<move_iterator<_Iterator>> = true;
   } // namespace __detail
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+    template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+        [[no_unique_address]] _Out out;
+        [[no_unique_address]] _Tp value;
+
+        template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+        && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+        template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+        && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+
+#endif // __glibcxx_ranges_iota
+
+
   struct __equal_fn
   {
     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
-- 
2.25.1


From 40d192554509812f64ed1b0afc16d4a85f67b7ce Mon Sep 17 00:00:00 2001
From: Michael Levine <mlevine55@bloomberg.net>
Date: Fri, 17 May 2024 11:44:26 -0400
Subject: [PATCH 11/11] Updated an import comment

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/std/numeric | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index 3a4917b89f5..d88f7f02137 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -66,7 +66,7 @@
 #endif
 
 #if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-#include <bits/ranges_algobase.h> // for std::out_value_result as used by std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from which _Range is used by std::ranges::iota
+#include <bits/ranges_algobase.h> // for out_value_result as used by std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from which _Range is used by std::ranges::iota
 #endif // __glibcxx_ranges_iota
 
 #if __cplusplus >= 201402L
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]
  2024-05-17 16:59 ` [PATCH v2] libstdc++: Fix std::ranges::iota " Michael Levine (BLOOMBERG/ 731 LEX)
@ 2024-05-23 22:41   ` Patrick Palka
  2024-05-24 13:56     ` [PATCH v3] libstdc++: Fix std::ranges::iota not " Michael Levine (BLOOMBERG/ 731 LEX)
  0 siblings, 1 reply; 13+ messages in thread
From: Patrick Palka @ 2024-05-23 22:41 UTC (permalink / raw)
  To: Michael Levine (BLOOMBERG/ 731 LEX); +Cc: gcc-patches, libstdc++

On Fri, 17 May 2024, Michael Levine (BLOOMBERG/ 731 LEX) wrote:

> This is the revised version of my patch incorporating the provided feedback from Patrick Palka and Jonathan Wakely.
> This patch fixes GCC Bug 108760: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> I moved out_value_result to <bits/ranges_algobase.h>, moved std::ranges:iota into <numeric>, removed my new test, and moved and renamed the existing test.

Nice, thanks!  The incremental changes seem good, but could you send a
single squashed patch containing all the changes?  That's what we'll end
up pushing after all.

> 
> I built my local version of gcc using the following configuration: $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto
> I then ran $ make -jN
> and $ make -jN install
> 
> Using the locally installed version, the following code compiled: https://godbolt.org/z/33EPeqd1b
> 
> I tested my changes by running: $ make check-c++ -jN -k
> I personally found it difficult to understand the results of running the tests.
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00
> To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
> Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
> 
> This patch fixes GCC Bug 108760: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including <algorithm> when it should have been sufficient to only include <numeric>.
> 
> When the patch is applied, the following code will compile: https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ ../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" --enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> 
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
  2024-05-23 22:41   ` Patrick Palka
@ 2024-05-24 13:56     ` Michael Levine (BLOOMBERG/ 731 LEX)
  2024-05-24 14:12       ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Levine (BLOOMBERG/ 731 LEX) @ 2024-05-24 13:56 UTC (permalink / raw)
  To: ppalka; +Cc: gcc-patches, libstdc++


[-- Attachment #1.1: Type: text/plain, Size: 2659 bytes --]

I've attached the v3 version of the patch as a single, squashed patch containing all of the changes.  I manually prepended my sign off to the patch.

From: ppalka@redhat.com At: 05/23/24 18:41:14 UTC-4:00To:  Michael Levine (BLOOMBERG/ 731 LEX ) 
Cc:  gcc-patches@gcc.gnu.org,  libstdc++@gcc.gnu.org
Subject: Re: [PATCH v2] libstdc++: Fix std::ranges::iota not included in numeric [PR108760]

On Fri, 17 May 2024, Michael Levine (BLOOMBERG/ 731 LEX) wrote:

> This is the revised version of my patch incorporating the provided feedback 
from Patrick Palka and Jonathan Wakely.
> This patch fixes GCC Bug 108760: 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> I moved out_value_result to <bits/ranges_algobase.h>, moved std::ranges:iota 
into <numeric>, removed my new test, and moved and renamed the existing test.

Nice, thanks!  The incremental changes seem good, but could you send a
single squashed patch containing all the changes?  That's what we'll end
up pushing after all.

> 
> I built my local version of gcc using the following configuration: $ 
../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
--enable-languages=c,c++,lto
> I then ran $ make -jN
> and $ make -jN install
> 
> Using the locally installed version, the following code compiled: 
https://godbolt.org/z/33EPeqd1b
> 
> I tested my changes by running: $ make check-c++ -jN -k
> I personally found it difficult to understand the results of running the 
tests.
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 04/17/24 14:24:24 UTC-4:00
> To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org
> Subject: [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric 
[PR108760]
> 
> This patch fixes GCC Bug 108760: 
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108760
> Before this patch, using std::ranges::iota required including <algorithm> 
when it should have been sufficient to only include <numeric>.
> 
> When the patch is applied, the following code will compile: 
https://godbolt.org/z/33EPeqd1b
> 
> I added a test case for this change as well.
> 
> I built my local version of gcc using the following configuration: $ 
../gcc/configure --disable-bootstrap --prefix="$(pwd)/_pfx/" 
--enable-languages=c,c++,lto
> 
> and I tested my changes by running: $ make check-c++ -jN -k
> 
> I ran this on the following OS:
> 
> Virtualization: wsl
> Operating System: Ubuntu 20.04.6 LTS
> Kernel: Linux 5.15.146.1-microsoft-standard-WSL2
> Architecture: x86-64
> 
> 
> 
> 
> 



[-- Attachment #2: 108760v3.patch --]
[-- Type: application/octet-stream, Size: 5860 bytes --]

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 62faff173bd..d258be0b93f 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3521,58 +3521,6 @@ namespace ranges
 
 #endif // __glibcxx_ranges_contains
 
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-  template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
-
-  struct __iota_fn
-  {
-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
-      requires indirectly_writable<_Out, const _Tp&>
-      constexpr iota_result<_Out, _Tp>
-      operator()(_Out __first, _Sent __last, _Tp __value) const
-      {
-	while (__first != __last)
-	  {
-	    *__first = static_cast<const _Tp&>(__value);
-	    ++__first;
-	    ++__value;
-	  }
-	return {std::move(__first), std::move(__value)};
-      }
-
-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
-      operator()(_Range&& __r, _Tp __value) const
-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
-  };
-
-  inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
-
 #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
 
   struct __find_last_fn
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index e26a73a27d6..965b36aed35 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -35,6 +35,7 @@
 #include <compare>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_iterator.h>
+#include <bits/stl_algobase.h> // __memcpy
 #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
 #include <bits/invoke.h>      // __invoke
 #include <bits/cpp_type_traits.h> // __is_byte
@@ -70,6 +71,32 @@ namespace ranges
 	__is_move_iterator<move_iterator<_Iterator>> = true;
   } // namespace __detail
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+    template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+        [[no_unique_address]] _Out out;
+        [[no_unique_address]] _Tp value;
+
+        template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+        && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+        template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+        && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+
+#endif // __glibcxx_ranges_iota
+
+
   struct __equal_fn
   {
     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index c912db4a519..d88f7f02137 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -65,6 +65,10 @@
 # include <parallel/numeric>
 #endif
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+#include <bits/ranges_algobase.h> // for out_value_result as used by std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from which _Range is used by std::ranges::iota
+#endif // __glibcxx_ranges_iota
+
 #if __cplusplus >= 201402L
 # include <type_traits>
 # include <bit>
@@ -726,6 +730,40 @@ namespace __detail
   /// @} group numeric_ops
 #endif // C++17
 
+namespace ranges
+{
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+  template<typename _Out, typename _Tp>
+  using iota_result = out_value_result<_Out, _Tp>;
+
+  struct __iota_fn
+  {
+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
+      requires indirectly_writable<_Out, const _Tp&>
+      constexpr iota_result<_Out, _Tp>
+      operator()(_Out __first, _Sent __last, _Tp __value) const
+      {
+	while (__first != __last)
+	  {
+	    *__first = static_cast<const _Tp&>(__value);
+	    ++__first;
+	    ++__value;
+	  }
+	return {std::move(__first), std::move(__value)};
+      }
+
+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
+      operator()(_Range&& __r, _Tp __value) const
+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
+  };
+
+  inline constexpr __iota_fn iota{};
+
+#endif // __glibcxx_ranges_iota
+} // namespace ranges
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
similarity index 96%
rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
index 61bf418b4da..040c48d91ce 100644
--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
@@ -1,6 +1,6 @@
 // { dg-do run { target c++23 } }
 
-#include <algorithm>
+#include <numeric>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
  2024-05-24 13:56     ` [PATCH v3] libstdc++: Fix std::ranges::iota not " Michael Levine (BLOOMBERG/ 731 LEX)
@ 2024-05-24 14:12       ` Jonathan Wakely
  2024-05-30 17:43         ` Michael Levine (BLOOMBERG/ 731 LEX)
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2024-05-24 14:12 UTC (permalink / raw)
  To: Michael Levine; +Cc: ppalka, gcc-patches, libstdc++

On 24/05/24 13:56 -0000, Michael Levine (BLOOMBERG/ 731 LEX) wrote:
>I've attached the v3 version of the patch as a single, squashed patch containing all of the changes.  I manually prepended my sign off to the patch.


>Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
>---
>diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
>index 62faff173bd..d258be0b93f 100644
>--- a/libstdc++-v3/include/bits/ranges_algo.h
>+++ b/libstdc++-v3/include/bits/ranges_algo.h
>@@ -3521,58 +3521,6 @@ namespace ranges
> 
> #endif // __glibcxx_ranges_contains
> 
>-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>-
>-  template<typename _Out, typename _Tp>
>-    struct out_value_result
>-    {
>-      [[no_unique_address]] _Out out;
>-      [[no_unique_address]] _Tp value;
>-
>-      template<typename _Out2, typename _Tp2>
>-	requires convertible_to<const _Out&, _Out2>
>-	  && convertible_to<const _Tp&, _Tp2>
>-	constexpr
>-	operator out_value_result<_Out2, _Tp2>() const &
>-	{ return {out, value}; }
>-
>-      template<typename _Out2, typename _Tp2>
>-	requires convertible_to<_Out, _Out2>
>-	  && convertible_to<_Tp, _Tp2>
>-	constexpr
>-	operator out_value_result<_Out2, _Tp2>() &&
>-	{ return {std::move(out), std::move(value)}; }
>-    };
>-
>-  template<typename _Out, typename _Tp>
>-    using iota_result = out_value_result<_Out, _Tp>;
>-
>-  struct __iota_fn
>-  {
>-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
>-      requires indirectly_writable<_Out, const _Tp&>
>-      constexpr iota_result<_Out, _Tp>
>-      operator()(_Out __first, _Sent __last, _Tp __value) const
>-      {
>-	while (__first != __last)
>-	  {
>-	    *__first = static_cast<const _Tp&>(__value);
>-	    ++__first;
>-	    ++__value;
>-	  }
>-	return {std::move(__first), std::move(__value)};
>-      }
>-
>-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>-      operator()(_Range&& __r, _Tp __value) const
>-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
>-  };
>-
>-  inline constexpr __iota_fn iota{};
>-
>-#endif // __glibcxx_ranges_iota
>-
> #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
> 
>   struct __find_last_fn
>diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
>index e26a73a27d6..965b36aed35 100644
>--- a/libstdc++-v3/include/bits/ranges_algobase.h
>+++ b/libstdc++-v3/include/bits/ranges_algobase.h
>@@ -35,6 +35,7 @@
> #include <compare>
> #include <bits/stl_iterator_base_funcs.h>
> #include <bits/stl_iterator.h>
>+#include <bits/stl_algobase.h> // __memcpy

Why is this being added here? What is __memcpy?

I don't think out_value_result requires any new headers to be included
here, does it?

> #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
> #include <bits/invoke.h>      // __invoke
> #include <bits/cpp_type_traits.h> // __is_byte
>@@ -70,6 +71,32 @@ namespace ranges
> 	__is_move_iterator<move_iterator<_Iterator>> = true;
>   } // namespace __detail
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+    template<typename _Out, typename _Tp>
>+    struct out_value_result
>+    {
>+        [[no_unique_address]] _Out out;
>+        [[no_unique_address]] _Tp value;
>+
>+        template<typename _Out2, typename _Tp2>
>+	requires convertible_to<const _Out&, _Out2>
>+        && convertible_to<const _Tp&, _Tp2>
>+	constexpr
>+	operator out_value_result<_Out2, _Tp2>() const &
>+	{ return {out, value}; }
>+
>+        template<typename _Out2, typename _Tp2>
>+	requires convertible_to<_Out, _Out2>
>+        && convertible_to<_Tp, _Tp2>
>+	constexpr
>+	operator out_value_result<_Out2, _Tp2>() &&
>+	{ return {std::move(out), std::move(value)}; }
>+    };
>+
>+#endif // __glibcxx_ranges_iota
>+
>+
>   struct __equal_fn
>   {
>     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
>diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
>index c912db4a519..d88f7f02137 100644
>--- a/libstdc++-v3/include/std/numeric
>+++ b/libstdc++-v3/include/std/numeric
>@@ -65,6 +65,10 @@
> # include <parallel/numeric>
> #endif
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+#include <bits/ranges_algobase.h> // for out_value_result as used by std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from which _Range is used by std::ranges::iota

We generally try to keep lines below 80 columns, or 120 at a push.
This is unnecessarily long, and I don't know what _Range is meant to
be (that's just a template parameter, not something defined in
<bits/ranges_algobase.h>. Please just use:

#include <bits/ranges_algobase.h> // for ranges::out_value_result

Otherwise this looks ready to go in, thanks.

>+#endif // __glibcxx_ranges_iota
>+
> #if __cplusplus >= 201402L
> # include <type_traits>
> # include <bit>
>@@ -726,6 +730,40 @@ namespace __detail
>   /// @} group numeric_ops
> #endif // C++17
> 
>+namespace ranges
>+{
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+  template<typename _Out, typename _Tp>
>+  using iota_result = out_value_result<_Out, _Tp>;
>+
>+  struct __iota_fn
>+  {
>+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
>+      requires indirectly_writable<_Out, const _Tp&>
>+      constexpr iota_result<_Out, _Tp>
>+      operator()(_Out __first, _Sent __last, _Tp __value) const
>+      {
>+	while (__first != __last)
>+	  {
>+	    *__first = static_cast<const _Tp&>(__value);
>+	    ++__first;
>+	    ++__value;
>+	  }
>+	return {std::move(__first), std::move(__value)};
>+      }
>+
>+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>+      operator()(_Range&& __r, _Tp __value) const
>+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
>+  };
>+
>+  inline constexpr __iota_fn iota{};
>+
>+#endif // __glibcxx_ranges_iota
>+} // namespace ranges
>+
> _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace std
> 
>diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>similarity index 96%
>rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
>index 61bf418b4da..040c48d91ce 100644
>--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>@@ -1,6 +1,6 @@
> // { dg-do run { target c++23 } }
> 
>-#include <algorithm>
>+#include <numeric>
> #include <testsuite_hooks.h>
> #include <testsuite_iterators.h>
> 


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
  2024-05-24 14:12       ` Jonathan Wakely
@ 2024-05-30 17:43         ` Michael Levine (BLOOMBERG/ 731 LEX)
  2024-06-06 20:49           ` Michael Levine (BLOOMBERG/ 731 LEX)
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Levine (BLOOMBERG/ 731 LEX) @ 2024-05-30 17:43 UTC (permalink / raw)
  To: jwakely; +Cc: ppalka, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 8031 bytes --]

When I remove <bits/stl_algobase.h> for importing __memcmp (my apologies for writing __memcpy) from libstdc++-v3/include/bits/ranges_algobase.h and try to rerun the code, I get the following error:

In file included from $HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/numeric:69,
                 from ranges-iota-fix.cpp:1:
$HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h: In member function ‘constexpr bool std::ranges::__equal_fn::operator()(_Iter1, _Sent1, _Iter2, _Sent2, _Pred, _Proj1, _Proj2) const’:
$HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h:143:32: error: ‘__memcmp’ is not a member of ‘std’; did you mean ‘__memcmpable’?
  143 |                   return !std::__memcmp(__first1, __first2, __len);
      |                                ^~~~~~~~
      |                                __memcmpable

From: jwakely@redhat.com At: 05/24/24 10:12:57 UTC-4:00To:  Michael Levine (BLOOMBERG/ 731 LEX ) 
Cc:  ppalka@redhat.com,  gcc-patches@gcc.gnu.org,  libstdc++@gcc.gnu.org
Subject: Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]

On 24/05/24 13:56 -0000, Michael Levine (BLOOMBERG/ 731 LEX) wrote:
>I've attached the v3 version of the patch as a single, squashed patch 
containing all of the changes.  I manually prepended my sign off to the patch.


>Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
>---
>diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
>index 62faff173bd..d258be0b93f 100644
>--- a/libstdc++-v3/include/bits/ranges_algo.h
>+++ b/libstdc++-v3/include/bits/ranges_algo.h
>@@ -3521,58 +3521,6 @@ namespace ranges
> 
> #endif // __glibcxx_ranges_contains
> 
>-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>-
>-  template<typename _Out, typename _Tp>
>-    struct out_value_result
>-    {
>-      [[no_unique_address]] _Out out;
>-      [[no_unique_address]] _Tp value;
>-
>-      template<typename _Out2, typename _Tp2>
>-        requires convertible_to<const _Out&, _Out2>
>-    && convertible_to<const _Tp&, _Tp2>
>-        constexpr
>-      operator out_value_result<_Out2, _Tp2>() const &
>-     { return {out, value}; }
>-
>-      template<typename _Out2, typename _Tp2>
>-  requires convertible_to<_Out, _Out2>
>-       && convertible_to<_Tp, _Tp2>
>-   constexpr
>-      operator out_value_result<_Out2, _Tp2>() &&
>-      { return {std::move(out), std::move(value)}; }
>-    };
>-
>-  template<typename _Out, typename _Tp>
>-    using iota_result = out_value_result<_Out, _Tp>;
>-
>-  struct __iota_fn
>-  {
>-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, 
weakly_incrementable _Tp>
>-      requires indirectly_writable<_Out, const _Tp&>
>-      constexpr iota_result<_Out, _Tp>
>-      operator()(_Out __first, _Sent __last, _Tp __value) const
>-      {
>-    while (__first != __last)
>-        {
>-        *__first = static_cast<const _Tp&>(__value);
>-         ++__first;
>-     ++__value;
>-   }
>-    return {std::move(__first), std::move(__value)};
>-      }
>-
>-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>-      operator()(_Range&& __r, _Tp __value) const
>-      { return (*this)(ranges::begin(__r), ranges::end(__r), 
std::move(__value)); }
>-  };
>-
>-  inline constexpr __iota_fn iota{};
>-
>-#endif // __glibcxx_ranges_iota
>-
> #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
> 
>   struct __find_last_fn
>diff --git a/libstdc++-v3/include/bits/ranges_algobase.h 
b/libstdc++-v3/include/bits/ranges_algobase.h
>index e26a73a27d6..965b36aed35 100644
>--- a/libstdc++-v3/include/bits/ranges_algobase.h
>+++ b/libstdc++-v3/include/bits/ranges_algobase.h
>@@ -35,6 +35,7 @@
> #include <compare>
> #include <bits/stl_iterator_base_funcs.h>
> #include <bits/stl_iterator.h>
>+#include <bits/stl_algobase.h> // __memcpy

Why is this being added here? What is __memcpy?

I don't think out_value_result requires any new headers to be included
here, does it?

> #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
> #include <bits/invoke.h>      // __invoke
> #include <bits/cpp_type_traits.h> // __is_byte
>@@ -70,6 +71,32 @@ namespace ranges
>    __is_move_iterator<move_iterator<_Iterator>> = true;
>   } // namespace __detail
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+    template<typename _Out, typename _Tp>
>+    struct out_value_result
>+    {
>+        [[no_unique_address]] _Out out;
>+        [[no_unique_address]] _Tp value;
>+
>+        template<typename _Out2, typename _Tp2>
>+        requires convertible_to<const _Out&, _Out2>
>+        && convertible_to<const _Tp&, _Tp2>
>+    constexpr
>+      operator out_value_result<_Out2, _Tp2>() const &
>+     { return {out, value}; }
>+
>+        template<typename _Out2, typename _Tp2>
>+        requires convertible_to<_Out, _Out2>
>+        && convertible_to<_Tp, _Tp2>
>+  constexpr
>+      operator out_value_result<_Out2, _Tp2>() &&
>+      { return {std::move(out), std::move(value)}; }
>+    };
>+
>+#endif // __glibcxx_ranges_iota
>+
>+
>   struct __equal_fn
>   {
>     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
>diff --git a/libstdc++-v3/include/std/numeric 
b/libstdc++-v3/include/std/numeric
>index c912db4a519..d88f7f02137 100644
>--- a/libstdc++-v3/include/std/numeric
>+++ b/libstdc++-v3/include/std/numeric
>@@ -65,6 +65,10 @@
> # include <parallel/numeric>
> #endif
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+#include <bits/ranges_algobase.h> // for out_value_result as used by 
std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from 
which _Range is used by std::ranges::iota

We generally try to keep lines below 80 columns, or 120 at a push.
This is unnecessarily long, and I don't know what _Range is meant to
be (that's just a template parameter, not something defined in
<bits/ranges_algobase.h>. Please just use:

#include <bits/ranges_algobase.h> // for ranges::out_value_result

Otherwise this looks ready to go in, thanks.

>+#endif // __glibcxx_ranges_iota
>+
> #if __cplusplus >= 201402L
> # include <type_traits>
> # include <bit>
>@@ -726,6 +730,40 @@ namespace __detail
>   /// @} group numeric_ops
> #endif // C++17
> 
>+namespace ranges
>+{
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+  template<typename _Out, typename _Tp>
>+  using iota_result = out_value_result<_Out, _Tp>;
>+
>+  struct __iota_fn
>+  {
>+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, 
weakly_incrementable _Tp>
>+      requires indirectly_writable<_Out, const _Tp&>
>+      constexpr iota_result<_Out, _Tp>
>+      operator()(_Out __first, _Sent __last, _Tp __value) const
>+      {
>+       while (__first != __last)
>+        {
>+        *__first = static_cast<const _Tp&>(__value);
>+         ++__first;
>+     ++__value;
>+   }
>+    return {std::move(__first), std::move(__value)};
>+      }
>+
>+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>+      operator()(_Range&& __r, _Tp __value) const
>+      { return (*this)(ranges::begin(__r), ranges::end(__r), 
std::move(__value)); }
>+  };
>+
>+  inline constexpr __iota_fn iota{};
>+
>+#endif // __glibcxx_ranges_iota
>+} // namespace ranges
>+
> _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace std
> 
>diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc 
b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>similarity index 96%
>rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
>index 61bf418b4da..040c48d91ce 100644
>--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>@@ -1,6 +1,6 @@
> // { dg-do run { target c++23 } }
> 
>-#include <algorithm>
>+#include <numeric>
> #include <testsuite_hooks.h>
> #include <testsuite_iterators.h>
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
  2024-05-30 17:43         ` Michael Levine (BLOOMBERG/ 731 LEX)
@ 2024-06-06 20:49           ` Michael Levine (BLOOMBERG/ 731 LEX)
  2024-06-07  8:50             ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Michael Levine (BLOOMBERG/ 731 LEX) @ 2024-06-06 20:49 UTC (permalink / raw)
  To: jwakely; +Cc: ppalka, gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 8665 bytes --]

To test the theory that this issue was unrelated to my patch, I moved the out_value_result definition into std/numeric and restored the version of bits/ranges_algobase.h to the version in master.  I kept the include line "include <bits/ranges_algobase.h>" in std/numeric even though it wasn't being used.  With the include line I see the same error about __memcmp is not a member of 'std'. 

From: Michael Levine (BLOOMBERG/ 731 LEX) At: 05/30/24 13:43:58 UTC-4:00To:  jwakely@redhat.com
Cc:  ppalka@redhat.com,  gcc-patches@gcc.gnu.org,  libstdc++@gcc.gnu.org
Subject: Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
When I remove <bits/stl_algobase.h> for importing __memcmp (my apologies for writing __memcpy) from libstdc++-v3/include/bits/ranges_algobase.h and try to rerun the code, I get the following error:

In file included from $HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/numeric:69,
                 from ranges-iota-fix.cpp:1:
$HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h: In member function ‘constexpr bool std::ranges::__equal_fn::operator()(_Iter1, _Sent1, _Iter2, _Sent2, _Pred, _Proj1, _Proj2) const’:
$HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h:143:32: error: ‘__memcmp’ is not a member of ‘std’; did you mean ‘__memcmpable’?
  143 |                   return !std::__memcmp(__first1, __first2, __len);
      |                                ^~~~~~~~
      |                                __memcmpable

From: jwakely@redhat.com At: 05/24/24 10:12:57 UTC-4:00To:  Michael Levine (BLOOMBERG/ 731 LEX ) 
Cc:  ppalka@redhat.com,  gcc-patches@gcc.gnu.org,  libstdc++@gcc.gnu.org
Subject: Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]

On 24/05/24 13:56 -0000, Michael Levine (BLOOMBERG/ 731 LEX) wrote:
>I've attached the v3 version of the patch as a single, squashed patch 
containing all of the changes.  I manually prepended my sign off to the patch.


>Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
>---
>diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
>index 62faff173bd..d258be0b93f 100644
>--- a/libstdc++-v3/include/bits/ranges_algo.h
>+++ b/libstdc++-v3/include/bits/ranges_algo.h
>@@ -3521,58 +3521,6 @@ namespace ranges
> 
> #endif // __glibcxx_ranges_contains
> 
>-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>-
>-  template<typename _Out, typename _Tp>
>-    struct out_value_result
>-    {
>-      [[no_unique_address]] _Out out;
>-      [[no_unique_address]] _Tp value;
>-
>-      template<typename _Out2, typename _Tp2>
>-        requires convertible_to<const _Out&, _Out2>
>-    && convertible_to<const _Tp&, _Tp2>
>-        constexpr
>-      operator out_value_result<_Out2, _Tp2>() const &
>-     { return {out, value}; }
>-
>-      template<typename _Out2, typename _Tp2>
>-  requires convertible_to<_Out, _Out2>
>-       && convertible_to<_Tp, _Tp2>
>-   constexpr
>-      operator out_value_result<_Out2, _Tp2>() &&
>-      { return {std::move(out), std::move(value)}; }
>-    };
>-
>-  template<typename _Out, typename _Tp>
>-    using iota_result = out_value_result<_Out, _Tp>;
>-
>-  struct __iota_fn
>-  {
>-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, 
weakly_incrementable _Tp>
>-      requires indirectly_writable<_Out, const _Tp&>
>-      constexpr iota_result<_Out, _Tp>
>-      operator()(_Out __first, _Sent __last, _Tp __value) const
>-      {
>-    while (__first != __last)
>-        {
>-        *__first = static_cast<const _Tp&>(__value);
>-         ++__first;
>-     ++__value;
>-   }
>-    return {std::move(__first), std::move(__value)};
>-      }
>-
>-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>-      operator()(_Range&& __r, _Tp __value) const
>-      { return (*this)(ranges::begin(__r), ranges::end(__r), 
std::move(__value)); }
>-  };
>-
>-  inline constexpr __iota_fn iota{};
>-
>-#endif // __glibcxx_ranges_iota
>-
> #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
> 
>   struct __find_last_fn
>diff --git a/libstdc++-v3/include/bits/ranges_algobase.h 
b/libstdc++-v3/include/bits/ranges_algobase.h
>index e26a73a27d6..965b36aed35 100644
>--- a/libstdc++-v3/include/bits/ranges_algobase.h
>+++ b/libstdc++-v3/include/bits/ranges_algobase.h
>@@ -35,6 +35,7 @@
> #include <compare>
> #include <bits/stl_iterator_base_funcs.h>
> #include <bits/stl_iterator.h>
>+#include <bits/stl_algobase.h> // __memcpy

Why is this being added here? What is __memcpy?

I don't think out_value_result requires any new headers to be included
here, does it?

> #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
> #include <bits/invoke.h>      // __invoke
> #include <bits/cpp_type_traits.h> // __is_byte
>@@ -70,6 +71,32 @@ namespace ranges
>  __is_move_iterator<move_iterator<_Iterator>> = true;
>   } // namespace __detail
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+    template<typename _Out, typename _Tp>
>+    struct out_value_result
>+    {
>+        [[no_unique_address]] _Out out;
>+        [[no_unique_address]] _Tp value;
>+
>+        template<typename _Out2, typename _Tp2>
>+  requires convertible_to<const _Out&, _Out2>
>+        && convertible_to<const _Tp&, _Tp2>
>+    constexpr
>+      operator out_value_result<_Out2, _Tp2>() const &
>+     { return {out, value}; }
>+
>+        template<typename _Out2, typename _Tp2>
>+        requires convertible_to<_Out, _Out2>
>+        && convertible_to<_Tp, _Tp2>
>+  constexpr
>+      operator out_value_result<_Out2, _Tp2>() &&
>+      { return {std::move(out), std::move(value)}; }
>+    };
>+
>+#endif // __glibcxx_ranges_iota
>+
>+
>   struct __equal_fn
>   {
>     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
>diff --git a/libstdc++-v3/include/std/numeric 
b/libstdc++-v3/include/std/numeric
>index c912db4a519..d88f7f02137 100644
>--- a/libstdc++-v3/include/std/numeric
>+++ b/libstdc++-v3/include/std/numeric
>@@ -65,6 +65,10 @@
> # include <parallel/numeric>
> #endif
> 
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+#include <bits/ranges_algobase.h> // for out_value_result as used by 
std::ranges::iota.  It transitively also brings in <bits/ranges_base.h>, from 
which _Range is used by std::ranges::iota

We generally try to keep lines below 80 columns, or 120 at a push.
This is unnecessarily long, and I don't know what _Range is meant to
be (that's just a template parameter, not something defined in
<bits/ranges_algobase.h>. Please just use:

#include <bits/ranges_algobase.h> // for ranges::out_value_result

Otherwise this looks ready to go in, thanks.

>+#endif // __glibcxx_ranges_iota
>+
> #if __cplusplus >= 201402L
> # include <type_traits>
> # include <bit>
>@@ -726,6 +730,40 @@ namespace __detail
>   /// @} group numeric_ops
> #endif // C++17
> 
>+namespace ranges
>+{
>+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
>+
>+  template<typename _Out, typename _Tp>
>+  using iota_result = out_value_result<_Out, _Tp>;
>+
>+  struct __iota_fn
>+  {
>+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, 
weakly_incrementable _Tp>
>+      requires indirectly_writable<_Out, const _Tp&>
>+      constexpr iota_result<_Out, _Tp>
>+      operator()(_Out __first, _Sent __last, _Tp __value) const
>+      {
>+     while (__first != __last)
>+        {
>+        *__first = static_cast<const _Tp&>(__value);
>+         ++__first;
>+     ++__value;
>+   }
>+    return {std::move(__first), std::move(__value)};
>+      }
>+
>+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
>+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
>+      operator()(_Range&& __r, _Tp __value) const
>+      { return (*this)(ranges::begin(__r), ranges::end(__r), 
std::move(__value)); }
>+  };
>+
>+  inline constexpr __iota_fn iota{};
>+
>+#endif // __glibcxx_ranges_iota
>+} // namespace ranges
>+
> _GLIBCXX_END_NAMESPACE_VERSION
> } // namespace std
> 
>diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc 
b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>similarity index 96%
>rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
>index 61bf418b4da..040c48d91ce 100644
>--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
>+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
>@@ -1,6 +1,6 @@
> // { dg-do run { target c++23 } }
> 
>-#include <algorithm>
>+#include <numeric>
> #include <testsuite_hooks.h>
> #include <testsuite_iterators.h>
> 



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
  2024-06-06 20:49           ` Michael Levine (BLOOMBERG/ 731 LEX)
@ 2024-06-07  8:50             ` Jonathan Wakely
  2024-06-08 15:03               ` [committed v4] libstdc++: Fix std::ranges::iota is not included " Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2024-06-07  8:50 UTC (permalink / raw)
  To: Michael Levine; +Cc: ppalka, gcc-patches, libstdc++

On Thu, 6 Jun 2024 at 21:49, Michael Levine (BLOOMBERG/ 731 LEX)
<mlevine55@bloomberg.net> wrote:
>
> To test the theory that this issue was unrelated to my patch, I moved the out_value_result definition into std/numeric and restored the version of bits/ranges_algobase.h to the version in master. I kept the include line "include <bits/ranges_algobase.h>" in std/numeric even though it wasn't being used. With the include line I see the same error about __memcmp is not a member of 'std'.

Thanks, I'll fix that separately and then apply your patch for iota.


>
> From: Michael Levine (BLOOMBERG/ 731 LEX) At: 05/30/24 13:43:58 UTC-4:00
> To: jwakely@redhat.com
> Cc: ppalka@redhat.com, gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
> Subject: Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
>
> When I remove <bits/stl_algobase.h> for importing __memcmp (my apologies for writing __memcpy) from libstdc++-v3/include/bits/ranges_algobase.h and try to rerun the code, I get the following error:
>
> In file included from $HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/numeric:69,
> from ranges-iota-fix.cpp:1:
> $HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h: In member function ‘constexpr bool std::ranges::__equal_fn::operator()(_Iter1, _Sent1, _Iter2, _Sent2, _Pred, _Proj1, _Proj2) const’:
> $HOME/projects/objdirforgcc/_pfx/include/c++/15.0.0/bits/ranges_algobase.h:143:32: error: ‘__memcmp’ is not a member of ‘std’; did you mean ‘__memcmpable’?
> 143 | return !std::__memcmp(__first1, __first2, __len);
> | ^~~~~~~~
> | __memcmpable
>
> From: jwakely@redhat.com At: 05/24/24 10:12:57 UTC-4:00
> To: Michael Levine (BLOOMBERG/ 731 LEX )
> Cc: ppalka@redhat.com, gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
> Subject: Re: [PATCH v3] libstdc++: Fix std::ranges::iota not in numeric [PR108760]
>
> On 24/05/24 13:56 -0000, Michael Levine (BLOOMBERG/ 731 LEX) wrote:
> >I've attached the v3 version of the patch as a single, squashed patch
> containing all of the changes. I manually prepended my sign off to the patch.
>
>
> >Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
> >---
> >diff --git a/libstdc++-v3/include/bits/ranges_algo.h
> b/libstdc++-v3/include/bits/ranges_algo.h
> >index 62faff173bd..d258be0b93f 100644
> >--- a/libstdc++-v3/include/bits/ranges_algo.h
> >+++ b/libstdc++-v3/include/bits/ranges_algo.h
> >@@ -3521,58 +3521,6 @@ namespace ranges
> >
> > #endif // __glibcxx_ranges_contains
> >
> >-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> >-
> >- template<typename _Out, typename _Tp>
> >- struct out_value_result
> >- {
> >- [[no_unique_address]] _Out out;
> >- [[no_unique_address]] _Tp value;
> >-
> >- template<typename _Out2, typename _Tp2>
> >- requires convertible_to<const _Out&, _Out2>
> >- && convertible_to<const _Tp&, _Tp2>
> >- constexpr
> >- operator out_value_result<_Out2, _Tp2>() const &
> >- { return {out, value}; }
> >-
> >- template<typename _Out2, typename _Tp2>
> >- requires convertible_to<_Out, _Out2>
> >- && convertible_to<_Tp, _Tp2>
> >- constexpr
> >- operator out_value_result<_Out2, _Tp2>() &&
> >- { return {std::move(out), std::move(value)}; }
> >- };
> >-
> >- template<typename _Out, typename _Tp>
> >- using iota_result = out_value_result<_Out, _Tp>;
> >-
> >- struct __iota_fn
> >- {
> >- template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent,
> weakly_incrementable _Tp>
> >- requires indirectly_writable<_Out, const _Tp&>
> >- constexpr iota_result<_Out, _Tp>
> >- operator()(_Out __first, _Sent __last, _Tp __value) const
> >- {
> >- while (__first != __last)
> >- {
> >- *__first = static_cast<const _Tp&>(__value);
> >- ++__first;
> >- ++__value;
> >- }
> >- return {std::move(__first), std::move(__value)};
> >- }
> >-
> >- template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> >- constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> >- operator()(_Range&& __r, _Tp __value) const
> >- { return (*this)(ranges::begin(__r), ranges::end(__r),
> std::move(__value)); }
> >- };
> >-
> >- inline constexpr __iota_fn iota{};
> >-
> >-#endif // __glibcxx_ranges_iota
> >-
> > #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
> >
> > struct __find_last_fn
> >diff --git a/libstdc++-v3/include/bits/ranges_algobase.h
> b/libstdc++-v3/include/bits/ranges_algobase.h
> >index e26a73a27d6..965b36aed35 100644
> >--- a/libstdc++-v3/include/bits/ranges_algobase.h
> >+++ b/libstdc++-v3/include/bits/ranges_algobase.h
> >@@ -35,6 +35,7 @@
> > #include <compare>
> > #include <bits/stl_iterator_base_funcs.h>
> > #include <bits/stl_iterator.h>
> >+#include <bits/stl_algobase.h> // __memcpy
>
> Why is this being added here? What is __memcpy?
>
> I don't think out_value_result requires any new headers to be included
> here, does it?
>
> > #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
> > #include <bits/invoke.h> // __invoke
> > #include <bits/cpp_type_traits.h> // __is_byte
> >@@ -70,6 +71,32 @@ namespace ranges
> > __is_move_iterator<move_iterator<_Iterator>> = true;
> > } // namespace __detail
> >
> >+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> >+
> >+ template<typename _Out, typename _Tp>
> >+ struct out_value_result
> >+ {
> >+ [[no_unique_address]] _Out out;
> >+ [[no_unique_address]] _Tp value;
> >+
> >+ template<typename _Out2, typename _Tp2>
> >+ requires convertible_to<const _Out&, _Out2>
> >+ && convertible_to<const _Tp&, _Tp2>
> >+ constexpr
> >+ operator out_value_result<_Out2, _Tp2>() const &
> >+ { return {out, value}; }
> >+
> >+ template<typename _Out2, typename _Tp2>
> >+ requires convertible_to<_Out, _Out2>
> >+ && convertible_to<_Tp, _Tp2>
> >+ constexpr
> >+ operator out_value_result<_Out2, _Tp2>() &&
> >+ { return {std::move(out), std::move(value)}; }
> >+ };
> >+
> >+#endif // __glibcxx_ranges_iota
> >+
> >+
> > struct __equal_fn
> > {
> > template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
> >diff --git a/libstdc++-v3/include/std/numeric
> b/libstdc++-v3/include/std/numeric
> >index c912db4a519..d88f7f02137 100644
> >--- a/libstdc++-v3/include/std/numeric
> >+++ b/libstdc++-v3/include/std/numeric
> >@@ -65,6 +65,10 @@
> > # include <parallel/numeric>
> > #endif
> >
> >+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> >+#include <bits/ranges_algobase.h> // for out_value_result as used by
> std::ranges::iota. It transitively also brings in <bits/ranges_base.h>, from
> which _Range is used by std::ranges::iota
>
> We generally try to keep lines below 80 columns, or 120 at a push.
> This is unnecessarily long, and I don't know what _Range is meant to
> be (that's just a template parameter, not something defined in
> <bits/ranges_algobase.h>. Please just use:
>
> #include <bits/ranges_algobase.h> // for ranges::out_value_result
>
> Otherwise this looks ready to go in, thanks.
>
> >+#endif // __glibcxx_ranges_iota
> >+
> > #if __cplusplus >= 201402L
> > # include <type_traits>
> > # include <bit>
> >@@ -726,6 +730,40 @@ namespace __detail
> > /// @} group numeric_ops
> > #endif // C++17
> >
> >+namespace ranges
> >+{
> >+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
> >+
> >+ template<typename _Out, typename _Tp>
> >+ using iota_result = out_value_result<_Out, _Tp>;
> >+
> >+ struct __iota_fn
> >+ {
> >+ template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent,
> weakly_incrementable _Tp>
> >+ requires indirectly_writable<_Out, const _Tp&>
> >+ constexpr iota_result<_Out, _Tp>
> >+ operator()(_Out __first, _Sent __last, _Tp __value) const
> >+ {
> >+ while (__first != __last)
> >+ {
> >+ *__first = static_cast<const _Tp&>(__value);
> >+ ++__first;
> >+ ++__value;
> >+ }
> >+ return {std::move(__first), std::move(__value)};
> >+ }
> >+
> >+ template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
> >+ constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
> >+ operator()(_Range&& __r, _Tp __value) const
> >+ { return (*this)(ranges::begin(__r), ranges::end(__r),
> std::move(__value)); }
> >+ };
> >+
> >+ inline constexpr __iota_fn iota{};
> >+
> >+#endif // __glibcxx_ranges_iota
> >+} // namespace ranges
> >+
> > _GLIBCXX_END_NAMESPACE_VERSION
> > } // namespace std
> >
> >diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
> b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
> >similarity index 96%
> >rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
> >rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
> >index 61bf418b4da..040c48d91ce 100644
> >--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
> >+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
> >@@ -1,6 +1,6 @@
> > // { dg-do run { target c++23 } }
> >
> >-#include <algorithm>
> >+#include <numeric>
> > #include <testsuite_hooks.h>
> > #include <testsuite_iterators.h>
> >
>
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [committed v4] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
  2024-06-07  8:50             ` Jonathan Wakely
@ 2024-06-08 15:03               ` Jonathan Wakely
  2024-06-08 15:55                 ` Ulrich Drepper
  0 siblings, 1 reply; 13+ messages in thread
From: Jonathan Wakely @ 2024-06-08 15:03 UTC (permalink / raw)
  To: libstdc++, gcc-patches; +Cc: Michael Levine

From: Michael Levine <mlevine55@bloomberg.net>

I committed the missing include separately, and pushed Michael's change
as attached (with some whitespace tweaks and a changelog entry).

Thanks for the patch, Michael!

Tested x86_64-linux. Pushed to trunk.

I'm in two minds about backporting this one. It would be good to fix the
non-conformance problem for the release branches, but it also
potentially breaks some code that uses ranges::iota without including
<numeric>. Ideally we'd make ranges::iota available in *both* <numeric>
and <algorithm> for gcc-13 and gcc-14, as a transition aid. I'm not sure
I can be bothered to move it to a separate header to make that work, nor
to include all of bits/ranges_algo.h in <numeric>.

-- >8 --

Before this patch, using std::ranges::iota required including
<algorithm> when it should have been sufficient to only include
<numeric>.

libstdc++-v3/ChangeLog:

	PR libstdc++/108760
	* include/bits/ranges_algo.h (ranges::out_value_result):
	Move to <bits/ranges_algobase.h>.
	(ranges::iota_result, ranges::__iota_fn, ranges::iota): Move to
	<numeric>.
	* include/bits/ranges_algobase.h (ranges::out_value_result):
	Move to here.
	* include/std/numeric (ranges::iota_result, ranges::__iota_fn)
	(ranges::iota): Move to here.
	* testsuite/25_algorithms/iota/1.cc: Renamed to ...
	* testsuite/26_numerics/iota/2.cc: ... here.

Signed-off-by: Michael Levine <mlevine55@bloomberg.net>
---
 libstdc++-v3/include/bits/ranges_algo.h       | 52 -------------------
 libstdc++-v3/include/bits/ranges_algobase.h   | 24 +++++++++
 libstdc++-v3/include/std/numeric              | 38 ++++++++++++++
 .../iota/1.cc => 26_numerics/iota/2.cc}       |  2 +-
 4 files changed, 63 insertions(+), 53 deletions(-)
 rename libstdc++-v3/testsuite/{25_algorithms/iota/1.cc => 26_numerics/iota/2.cc} (96%)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index 62faff173bd..d258be0b93f 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3521,58 +3521,6 @@ namespace ranges
 
 #endif // __glibcxx_ranges_contains
 
-#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
-
-  template<typename _Out, typename _Tp>
-    struct out_value_result
-    {
-      [[no_unique_address]] _Out out;
-      [[no_unique_address]] _Tp value;
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<const _Out&, _Out2>
-	  && convertible_to<const _Tp&, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() const &
-	{ return {out, value}; }
-
-      template<typename _Out2, typename _Tp2>
-	requires convertible_to<_Out, _Out2>
-	  && convertible_to<_Tp, _Tp2>
-	constexpr
-	operator out_value_result<_Out2, _Tp2>() &&
-	{ return {std::move(out), std::move(value)}; }
-    };
-
-  template<typename _Out, typename _Tp>
-    using iota_result = out_value_result<_Out, _Tp>;
-
-  struct __iota_fn
-  {
-    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
-      requires indirectly_writable<_Out, const _Tp&>
-      constexpr iota_result<_Out, _Tp>
-      operator()(_Out __first, _Sent __last, _Tp __value) const
-      {
-	while (__first != __last)
-	  {
-	    *__first = static_cast<const _Tp&>(__value);
-	    ++__first;
-	    ++__value;
-	  }
-	return {std::move(__first), std::move(__value)};
-      }
-
-    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
-      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
-      operator()(_Range&& __r, _Tp __value) const
-      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
-  };
-
-  inline constexpr __iota_fn iota{};
-
-#endif // __glibcxx_ranges_iota
-
 #if __glibcxx_ranges_find_last >= 202207L // C++ >= 23
 
   struct __find_last_fn
diff --git a/libstdc++-v3/include/bits/ranges_algobase.h b/libstdc++-v3/include/bits/ranges_algobase.h
index e1f00838818..7ce5ac314f2 100644
--- a/libstdc++-v3/include/bits/ranges_algobase.h
+++ b/libstdc++-v3/include/bits/ranges_algobase.h
@@ -35,6 +35,7 @@
 #include <compare>
 #include <bits/stl_iterator_base_funcs.h>
 #include <bits/stl_iterator.h>
+#include <bits/stl_algobase.h> // __memcpy
 #include <bits/ranges_base.h> // ranges::begin, ranges::range etc.
 #include <bits/invoke.h>      // __invoke
 #include <bits/cpp_type_traits.h> // __is_byte
@@ -71,6 +72,29 @@ namespace ranges
 	__is_move_iterator<move_iterator<_Iterator>> = true;
   } // namespace __detail
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+  template<typename _Out, typename _Tp>
+    struct out_value_result
+    {
+      [[no_unique_address]] _Out out;
+      [[no_unique_address]] _Tp value;
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<const _Out&, _Out2>
+	  && convertible_to<const _Tp&, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() const &
+	{ return {out, value}; }
+
+      template<typename _Out2, typename _Tp2>
+	requires convertible_to<_Out, _Out2>
+	  && convertible_to<_Tp, _Tp2>
+	constexpr
+	operator out_value_result<_Out2, _Tp2>() &&
+	{ return {std::move(out), std::move(value)}; }
+    };
+#endif // __glibcxx_ranges_iota
+
   struct __equal_fn
   {
     template<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
diff --git a/libstdc++-v3/include/std/numeric b/libstdc++-v3/include/std/numeric
index c912db4a519..201bb8e74a1 100644
--- a/libstdc++-v3/include/std/numeric
+++ b/libstdc++-v3/include/std/numeric
@@ -89,6 +89,10 @@
 #define __glibcxx_want_saturation_arithmetic
 #include <bits/version.h>
 
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+# include <bits/ranges_algobase.h> // for ranges::out_value_result
+#endif
+
 #ifdef __glibcxx_saturation_arithmetic // C++ >= 26
 # include <bits/sat_arith.h>
 #endif
@@ -726,6 +730,40 @@ namespace __detail
   /// @} group numeric_ops
 #endif // C++17
 
+namespace ranges
+{
+#if __glibcxx_ranges_iota >= 202202L // C++ >= 23
+
+  template<typename _Out, typename _Tp>
+  using iota_result = out_value_result<_Out, _Tp>;
+
+  struct __iota_fn
+  {
+    template<input_or_output_iterator _Out, sentinel_for<_Out> _Sent, weakly_incrementable _Tp>
+      requires indirectly_writable<_Out, const _Tp&>
+      constexpr iota_result<_Out, _Tp>
+      operator()(_Out __first, _Sent __last, _Tp __value) const
+      {
+	while (__first != __last)
+	  {
+	    *__first = static_cast<const _Tp&>(__value);
+	    ++__first;
+	    ++__value;
+	  }
+	return {std::move(__first), std::move(__value)};
+      }
+
+    template<weakly_incrementable _Tp, output_range<const _Tp&> _Range>
+      constexpr iota_result<borrowed_iterator_t<_Range>, _Tp>
+      operator()(_Range&& __r, _Tp __value) const
+      { return (*this)(ranges::begin(__r), ranges::end(__r), std::move(__value)); }
+  };
+
+  inline constexpr __iota_fn iota{};
+
+#endif // __glibcxx_ranges_iota
+} // namespace ranges
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
similarity index 96%
rename from libstdc++-v3/testsuite/25_algorithms/iota/1.cc
rename to libstdc++-v3/testsuite/26_numerics/iota/2.cc
index 61bf418b4da..040c48d91ce 100644
--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
@@ -1,6 +1,6 @@
 // { dg-do run { target c++23 } }
 
-#include <algorithm>
+#include <numeric>
 #include <testsuite_hooks.h>
 #include <testsuite_iterators.h>
 
-- 
2.45.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [committed v4] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
  2024-06-08 15:03               ` [committed v4] libstdc++: Fix std::ranges::iota is not included " Jonathan Wakely
@ 2024-06-08 15:55                 ` Ulrich Drepper
  2024-06-08 19:23                   ` Jonathan Wakely
  0 siblings, 1 reply; 13+ messages in thread
From: Ulrich Drepper @ 2024-06-08 15:55 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: libstdc++, gcc-patches, Michael Levine

On Sat, Jun 8, 2024 at 5:03 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> I'm in two minds about backporting this one. It would be good to fix the
> non-conformance problem for the release branches, but it also
> potentially breaks some code that uses ranges::iota without including
> <numeric>.

I say add the change as soon as possible so that there is as little
code as possible relying on the non-standard header.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [committed v4] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760]
  2024-06-08 15:55                 ` Ulrich Drepper
@ 2024-06-08 19:23                   ` Jonathan Wakely
  0 siblings, 0 replies; 13+ messages in thread
From: Jonathan Wakely @ 2024-06-08 19:23 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: libstdc++, gcc-patches, Michael Levine

On Sat, 8 Jun 2024 at 16:56, Ulrich Drepper <drepper.fsp@gmail.com> wrote:
>
> On Sat, Jun 8, 2024 at 5:03 PM Jonathan Wakely <jwakely@redhat.com> wrote:
> > I'm in two minds about backporting this one. It would be good to fix the
> > non-conformance problem for the release branches, but it also
> > potentially breaks some code that uses ranges::iota without including
> > <numeric>.
>
> I say add the change as soon as possible so that there is as little
> code as possible relying on the non-standard header.

Yes, that's good rationale for doing the backports.


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-06-08 19:24 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-17 18:24 [PATCH] libstdc++: Fix std::ranges::iota is not included in numeric [PR108760] Michael Levine (BLOOMBERG/ 919 3RD A)
2024-04-18 21:58 ` Patrick Palka
2024-04-19  9:18   ` Jonathan Wakely
2024-05-17 16:59 ` [PATCH v2] libstdc++: Fix std::ranges::iota " Michael Levine (BLOOMBERG/ 731 LEX)
2024-05-23 22:41   ` Patrick Palka
2024-05-24 13:56     ` [PATCH v3] libstdc++: Fix std::ranges::iota not " Michael Levine (BLOOMBERG/ 731 LEX)
2024-05-24 14:12       ` Jonathan Wakely
2024-05-30 17:43         ` Michael Levine (BLOOMBERG/ 731 LEX)
2024-06-06 20:49           ` Michael Levine (BLOOMBERG/ 731 LEX)
2024-06-07  8:50             ` Jonathan Wakely
2024-06-08 15:03               ` [committed v4] libstdc++: Fix std::ranges::iota is not included " Jonathan Wakely
2024-06-08 15:55                 ` Ulrich Drepper
2024-06-08 19:23                   ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).