[gcc r15-3090] libstdc++: Implement P2997R1 changes to the indirect invocability concepts

2024-08-22 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:620232426bd83a79c81cd2be6f485834c618e920

commit r15-3090-g620232426bd83a79c81cd2be6f485834c618e920
Author: Patrick Palka 
Date:   Thu Aug 22 09:24:20 2024 -0400

libstdc++: Implement P2997R1 changes to the indirect invocability concepts

This implements the changes of this C++26 paper as a DR against C++20.

In passing this patch removes the std/ranges/version_c++23.cc test which
is now mostly obsolete after the version.def FTM refactoring, and instead
expands the __cpp_lib_ranges checks in another test so that it verifies
the exact value of the FTM on a per language version basis.

libstdc++-v3/ChangeLog:

* include/bits/iterator_concepts.h (indirectly_unary_invocable):
Relax as per P2997R1.
(indirectly_regular_unary_invocable): Likewise.
(indirect_unary_predicate): Likewise.
(indirect_binary_predicate): Likewise.
(indirect_equivalence_relation): Likewise.
(indirect_strict_weak_order): Likewise.
* include/bits/version.def (ranges): Update value for C++26.
* include/bits/version.h: Regenerate.
* testsuite/24_iterators/indirect_callable/p2997r1.cc: New test.
* testsuite/std/ranges/version_c++23.cc: Remove.
* testsuite/std/ranges/headers/ranges/synopsis.cc: Refine the
__cpp_lib_ranges checks.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/iterator_concepts.h  | 17 ++
 libstdc++-v3/include/bits/version.def  |  5 ++
 libstdc++-v3/include/bits/version.h|  7 ++-
 .../24_iterators/indirect_callable/p2997r1.cc  | 37 
 .../std/ranges/headers/ranges/synopsis.cc  |  6 +-
 libstdc++-v3/testsuite/std/ranges/version_c++23.cc | 70 --
 6 files changed, 57 insertions(+), 85 deletions(-)

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index 9306b7bd194c..d849ddc32fc2 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -724,7 +724,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 concept indirectly_unary_invocable = indirectly_readable<_Iter>
   && copy_constructible<_Fn> && invocable<_Fn&, __indirect_value_t<_Iter>>
   && invocable<_Fn&, iter_reference_t<_Iter>>
-  && invocable<_Fn&, iter_common_reference_t<_Iter>>
   && common_reference_with>,
   invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
@@ -733,15 +732,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   && copy_constructible<_Fn>
   && regular_invocable<_Fn&, __indirect_value_t<_Iter>>
   && regular_invocable<_Fn&, iter_reference_t<_Iter>>
-  && regular_invocable<_Fn&, iter_common_reference_t<_Iter>>
   && common_reference_with>,
   invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
   template
 concept indirect_unary_predicate = indirectly_readable<_Iter>
   && copy_constructible<_Fn> && predicate<_Fn&, __indirect_value_t<_Iter>>
-  && predicate<_Fn&, iter_reference_t<_Iter>>
-  && predicate<_Fn&, iter_common_reference_t<_Iter>>;
+  && predicate<_Fn&, iter_reference_t<_Iter>>;
 
   template
 concept indirect_binary_predicate
@@ -750,9 +747,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   && predicate<_Fn&, __indirect_value_t<_I1>, __indirect_value_t<_I2>>
   && predicate<_Fn&, __indirect_value_t<_I1>, iter_reference_t<_I2>>
   && predicate<_Fn&, iter_reference_t<_I1>, __indirect_value_t<_I2>>
-  && predicate<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>>
-  && predicate<_Fn&, iter_common_reference_t<_I1>,
-  iter_common_reference_t<_I2>>;
+  && predicate<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>>;
 
   template
 concept indirect_equivalence_relation
@@ -762,9 +757,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   && equivalence_relation<_Fn&, __indirect_value_t<_I1>, 
iter_reference_t<_I2>>
   && equivalence_relation<_Fn&, iter_reference_t<_I1>, 
__indirect_value_t<_I2>>
   && equivalence_relation<_Fn&, iter_reference_t<_I1>,
- iter_reference_t<_I2>>
-  && equivalence_relation<_Fn&, iter_common_reference_t<_I1>,
- iter_common_reference_t<_I2>>;
+ iter_reference_t<_I2>>;
 
   template
 concept indirect_strict_weak_order
@@ -773,9 +766,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   && strict_weak_order<_Fn&, __indirect_value_t<_I1>, 
__indirect_value_t<_I2>>
   && strict_weak_order<_Fn&, __indirect_value_t<_I1>, 
iter_reference_t<_I2>>
   && strict_weak_order<_Fn&, iter_reference_t<_I1>, 
__indirect_value_t<_I2>>
-  && strict_weak_order<_Fn&, iter_reference_t<_I1>, iter_reference_t<_I2>>
-  && strict_weak_order<_Fn&, iter_common_reference_t<_I1>,
-

[gcc r15-3091] libstdc++: Optimize std::projected

2024-08-22 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:51761c50f843d5be4e24172535e4524b5072f24c

commit r15-3091-g51761c50f843d5be4e24172535e4524b5072f24c
Author: Patrick Palka 
Date:   Thu Aug 22 09:24:39 2024 -0400

libstdc++: Optimize std::projected

Algorithms that are generalized to take projections typically default the
projection to std::identity, which is equivalent to no projection at all.
In that case, I believe we could shortcut the projection logic to return
the iterator unchanged rather than wrapping it.  This should reduce compile
times especially after P2609R3 which made the indirect invocability
concepts more expensive to check when actual projections are involved.

libstdc++-v3/ChangeLog:

* include/bits/iterator_concepts.h (__detail::__projected): Define
an optimized partial specialization for when the projection is
std::identity.
* testsuite/24_iterators/indirect_callable/projected.cc: Verify the
optimization.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/iterator_concepts.h  | 5 +
 libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc | 5 +
 2 files changed, 10 insertions(+)

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index d849ddc32fc2..642c709fee0c 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -803,6 +803,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  using __projected_Proj = _Proj;
};
   };
+
+// Optimize the common case of the projection being std::identity.
+template
+  struct __projected<_Iter, identity>
+  { using __type = _Iter; };
   } // namespace __detail
 
   /// [projected], projected
diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc 
b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
index 0eec42c2d5fa..9ab7db9d65df 100644
--- a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
+++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
@@ -22,7 +22,12 @@
 template
   using PI = std::projected;
 
+#if __GLIBCXX__
+// Verify our projected optimization.
+static_assert(std::same_as, int*>);
+#else
 static_assert(std::same_as::value_type, int>);
+#endif
 static_assert(std::same_as&>()), int&>);
 
 struct X


[gcc r15-3094] libstdc++: Add some missing ranges feature-test macro tests

2024-08-22 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:8e0da56f18b3678beee9d2bae27e08a0e122573a

commit r15-3094-g8e0da56f18b3678beee9d2bae27e08a0e122573a
Author: Patrick Palka 
Date:   Thu Aug 22 11:24:07 2024 -0400

libstdc++: Add some missing ranges feature-test macro tests

libstdc++-v3/ChangeLog:

* testsuite/25_algorithms/contains/1.cc: Verify value of
__cpp_lib_ranges_contains.
* testsuite/25_algorithms/find_last/1.cc: Verify value of
__cpp_lib_ranges_find_last.
* testsuite/26_numerics/iota/2.cc: Verify value of
__cpp_lib_ranges_iota.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/testsuite/25_algorithms/contains/1.cc  | 4 
 libstdc++-v3/testsuite/25_algorithms/find_last/1.cc | 4 
 libstdc++-v3/testsuite/26_numerics/iota/2.cc| 4 
 3 files changed, 12 insertions(+)

diff --git a/libstdc++-v3/testsuite/25_algorithms/contains/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
index 7d3fa048ef61..b44c06032e8a 100644
--- a/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
@@ -4,6 +4,10 @@
 #include 
 #include 
 
+#if __cpp_lib_ranges_contains != 202207L
+# error "Feature-test macro __cpp_lib_ranges_contains has wrong value in 
"
+#endif
+
 namespace ranges = std::ranges;
 
 void
diff --git a/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
index 911e22887d1d..8a40bb1a6b36 100644
--- a/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
@@ -4,6 +4,10 @@
 #include 
 #include 
 
+#if __cpp_lib_ranges_find_last != 202207L
+# error "Feature-test macro __cpp_lib_ranges_find_last has wrong value in 
"
+#endif
+
 namespace ranges = std::ranges;
 
 constexpr bool
diff --git a/libstdc++-v3/testsuite/26_numerics/iota/2.cc 
b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
index 040c48d91ce2..b14580b8be19 100644
--- a/libstdc++-v3/testsuite/26_numerics/iota/2.cc
+++ b/libstdc++-v3/testsuite/26_numerics/iota/2.cc
@@ -4,6 +4,10 @@
 #include 
 #include 
 
+#if __cpp_lib_ranges_iota != 202202L
+# error "Feature-test macro __cpp_lib_ranges_iota has wrong value in "
+#endif
+
 namespace ranges = std::ranges;
 
 void


[gcc r14-10654] libstdc++: use concrete return type for std::forward_like

2024-09-08 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:140aab25a4865433d987d73c57f4ddf11fdac1e2

commit r14-10654-g140aab25a4865433d987d73c57f4ddf11fdac1e2
Author: Patrick Palka 
Date:   Sat Aug 3 09:05:05 2024 -0400

libstdc++: use concrete return type for std::forward_like

Inspired by https://github.com/llvm/llvm-project/issues/101614 this
inverts the relationship between forward_like and __like_t so that
forward_like is defined in terms of __like_t and with a concrete return
type.  __like_t in turn is defined via partial specializations that
pattern match on the const- and reference-ness of T.

This turns out to be more SFINAE friendly and significantly cheaper
to compile than the previous implementation.

libstdc++-v3/ChangeLog:

* include/bits/move.h (__like_impl): New metafunction.
(__like_t): Redefine in terms of __like_impl.
(forward_like): Redefine in terms of __like_t.
* testsuite/20_util/forward_like/2_neg.cc: Don't expect
error outside the immediate context anymore.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 8256d5c0097dff00f9bdf9ee0c9d53bd7cec2802)

Diff:
---
 libstdc++-v3/include/bits/move.h   | 47 +++---
 .../testsuite/20_util/forward_like/2_neg.cc|  6 +--
 2 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h
index bb200c95964a..8397a01b6323 100644
--- a/libstdc++-v3/include/bits/move.h
+++ b/libstdc++-v3/include/bits/move.h
@@ -88,31 +88,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __glibcxx_forward_like // C++ >= 23
   template
-  [[nodiscard]]
-  constexpr decltype(auto)
-  forward_like(_Up&& __x) noexcept
-  {
-constexpr bool __as_rval = is_rvalue_reference_v<_Tp&&>;
-
-if constexpr (is_const_v>)
-  {
-   using _Up2 = remove_reference_t<_Up>;
-   if constexpr (__as_rval)
- return static_cast(__x);
-   else
- return static_cast(__x);
-  }
-else
-  {
-   if constexpr (__as_rval)
- return static_cast&&>(__x);
-   else
- return static_cast<_Up&>(__x);
-  }
-  }
+  struct __like_impl; // _Tp must be a reference and _Up an lvalue reference
+
+  template
+  struct __like_impl<_Tp&, _Up&>
+  { using type = _Up&; };
+
+  template
+  struct __like_impl
+  { using type = const _Up&; };
+
+  template
+  struct __like_impl<_Tp&&, _Up&>
+  { using type = _Up&&; };
+
+  template
+  struct __like_impl
+  { using type = const _Up&&; };
 
   template
-using __like_t = decltype(std::forward_like<_Tp>(std::declval<_Up>()));
+using __like_t = typename __like_impl<_Tp&&, _Up&>::type;
+
+  template
+  [[nodiscard]]
+  constexpr __like_t<_Tp, _Up>
+  forward_like(_Up&& __x) noexcept
+  { return static_cast<__like_t<_Tp, _Up>>(__x); }
 #endif
 
   /**
diff --git a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc 
b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
index ff835af19151..5dafa419a7ea 100644
--- a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
@@ -2,9 +2,7 @@
 
 #include 
 
-auto x1 = std::forward_like(1); // { dg-error "here" }
+auto x1 = std::forward_like(1); // { dg-error "no match" }
 // { dg-error "forming reference to void" "" { target *-*-* } 0 }
-auto x2 = std::forward_like(1); // { dg-error "here" }
+auto x2 = std::forward_like(1); // { dg-error "no match" }
 // { dg-error "forming reference to qualified function" "" { target *-*-* } 0 }
-
-// { dg-prune-output "inconsistent deduction for auto return type" } // 
PR111484


[gcc r15-2117] c++: diagnose failed qualified lookup into current inst

2024-07-17 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:313afcfdabeab3e6705ac0bd1273627075be0023

commit r15-2117-g313afcfdabeab3e6705ac0bd1273627075be0023
Author: Patrick Palka 
Date:   Wed Jul 17 20:54:14 2024 -0400

c++: diagnose failed qualified lookup into current inst

When the scope of a qualified name is the current instantiation, and
qualified lookup finds nothing at template definition time, then we
know it'll find nothing at instantiation time (unless the current
instantiation has dependent bases).  So such qualified name lookup
failure can be diagnosed ahead of time as per [temp.res.general]/6.

This patch implements that, for qualified names of the form (where
the current instantiation is A):

  this->non_existent
  a.non_existent
  A::non_existent
  typename A::non_existent

It turns out we already optimistically attempt qualified lookup of
seemingly every qualified name, even when it's dependently scoped, and
then suppress issuing a lookup failure diagnostic after the fact.
So implementing this is mostly a matter of restricting the diagnostic
suppression to "dependentish" scopes (i.e. dependent scopes or the
current instantiation with dependent bases), rather than suppressing
for any dependently-typed scope as we currently do.

The cp_parser_conversion_function_id change is needed to avoid regressing
lookup/using8.C:

  using A::operator typename A::Nested*;

When looking up A::Nested we consider it not dependently scoped since
we entered A from cp_parser_conversion_function_id earlier.   But this
A is the implicit instantiation A not the primary template type A,
and so the lookup fails which we now diagnose.  This patch works around
this by not entering the template scope of a qualified conversion
function-id in this case, i.e. if we're in an expression vs declaration
context, by seeing if the type already went through finish_template_type
with entering_scope=true.

gcc/cp/ChangeLog:

* decl.cc (make_typename_type): Restrict name lookup failure
punting to dependentish_scope_p instead of dependent_type_p.
* error.cc (qualified_name_lookup_error): Improve diagnostic
when the scope is the current instantiation.
* parser.cc (cp_parser_diagnose_invalid_type_name): Likewise.
(cp_parser_conversion_function_id): Don't call push_scope on
a template scope unless we're in a declaration context.
(cp_parser_lookup_name): Restrict name lookup failure
punting to dependentish_scope_p instead of depedent_type_p.
* semantics.cc (finish_id_expression_1): Likewise.
* typeck.cc (finish_class_member_access_expr): Likewise.

libstdc++-v3/ChangeLog:

* include/experimental/socket
(basic_socket_iostream::basic_socket_iostream): Fix typo.
* include/tr2/dynamic_bitset
(__dynamic_bitset_base::_M_is_proper_subset_of): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/cpp0x/alignas18.C: Expect name lookup error for U::X.
* g++.dg/cpp0x/forw_enum13.C: Expect name lookup error for
D3::A and D4::A.
* g++.dg/parse/access13.C: Declare A::E::V to avoid name lookup
failure and preserve intent of the test.
* g++.dg/parse/enum11.C: Expect extra errors, matching the
non-template case.
* g++.dg/template/crash123.C: Avoid name lookup failure to
preserve intent of the test.
* g++.dg/template/crash124.C: Likewise.
* g++.dg/template/crash7.C: Adjust expected diagnostics.
* g++.dg/template/dtor6.C: Declare A::~A() to avoid name lookup
failure and preserve intent of the test.
* g++.dg/template/error22.C: Adjust expected diagnostics.
* g++.dg/template/static30.C: Avoid name lookup failure to
preserve intent of the test.
* g++.old-deja/g++.other/decl5.C: Adjust expected diagnostics.
* g++.dg/template/non-dependent34.C: New test.

Reviewed-by: Jason Merrill 

Diff:
---
 gcc/cp/decl.cc  |  2 +-
 gcc/cp/error.cc |  3 +-
 gcc/cp/parser.cc| 10 --
 gcc/cp/semantics.cc |  2 +-
 gcc/cp/typeck.cc|  2 +-
 gcc/testsuite/g++.dg/cpp0x/alignas18.C  |  3 +-
 gcc/testsuite/g++.dg/cpp0x/forw_enum13.C|  6 ++--
 gcc/testsuite/g++.dg/parse/access13.C   |  1 +
 gcc/testsuite/g++.dg/parse/enum11.C |  2 +-
 gcc/testsuite/g++.dg/template/crash123.C|  2 +-
 gcc/testsuite/g++.dg/template/crash124.C|  4 +--
 gcc/testsuite/g++.dg/template/crash7.C  |  6 ++--
 gcc/testsuite/g++.dg/template/dtor6.C   |  1

[gcc r14-9756] libstdc++: Allow adjacent __maybe_present_t fields to overlap

2024-04-02 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:0e64bbb8823f7b3757befc878ed177dfb59943d1

commit r14-9756-g0e64bbb8823f7b3757befc878ed177dfb59943d1
Author: Patrick Palka 
Date:   Tue Apr 2 13:07:07 2024 -0400

libstdc++: Allow adjacent __maybe_present_t fields to overlap

Currently __maybe_present_t maps to the same empty class
type independent of T.  This is suboptimal because it means adjacent
__maybe_present_t members with the [[no_unique_address]]
attribute can't overlap even if the conditionally present types are
different.

This patch turns this empty class type into a template parameterized by
the conditionally present type, so that

  [[no_unique_address]] __maybe_present_t _M_a;
  [[no_unique_address]] __maybe_present_t _M_b;

now overlap if T and U are different.

This patch goes a step further and also adds an optional integer
discriminator parameter to allow for overlapping when T and U are
the same.

libstdc++-v3/ChangeLog:

* include/std/ranges (ranges::__detail::_Empty): Rename to ...
(ranges::__detail::_Absent): ... this.  Turn into a template
parameterized by the absent type _Tp and discriminator _Disc.
(ranges::__detail::__maybe_present_t): Add an optional
discriminator parameter.
(slide_view::_M_cached_begin): Pass a discriminator argument to
__maybe_present_t.
(slide_view::_M_cached_end): Likewise.
* testsuite/std/ranges/adaptors/sizeof.cc: Verify the size of
slide_view is 3 instead 4 pointers.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges  | 13 -
 libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc |  4 
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 7d739852677..afce818376b 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -886,14 +886,17 @@ namespace views
 
 namespace __detail
 {
-  struct _Empty { };
+  template
+struct _Absent { };
 
   // Alias for a type that is conditionally present
   // (and is an empty type otherwise).
   // Data members using this alias should use [[no_unique_address]] so that
   // they take no space when not needed.
-  template
-using __maybe_present_t = __conditional_t<_Present, _Tp, _Empty>;
+  // The optional template parameter _Disc is for discriminating two otherwise
+  // equivalent absent types so that even they can overlap.
+  template
+using __maybe_present_t = __conditional_t<_Present, _Tp, _Absent<_Tp, 
_Disc>>;
 
   // Alias for a type that is conditionally const.
   template
@@ -6553,10 +6556,10 @@ namespace views::__adaptor
 range_difference_t<_Vp> _M_n;
 [[no_unique_address]]
   __detail::__maybe_present_t<__detail::__slide_caches_first<_Vp>,
- __detail::_CachedPosition<_Vp>> 
_M_cached_begin;
+ __detail::_CachedPosition<_Vp>, 0> 
_M_cached_begin;
 [[no_unique_address]]
   __detail::__maybe_present_t<__detail::__slide_caches_last<_Vp>,
- __detail::_CachedPosition<_Vp>> _M_cached_end;
+ __detail::_CachedPosition<_Vp>, 1> 
_M_cached_end;
 
 template class _Iterator;
 class _Sentinel;
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
index 12a9da3181d..08c01704d10 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc
@@ -49,3 +49,7 @@ static_assert(sizeof(ranges::lazy_split_view) == 4*ptr);
 
 static_assert
  (sizeof(ranges::reverse_view>) == 
3*ptr);
+
+#if __cpp_lib_ranges_slide
+static_assert(sizeof(ranges::slide_view) == 3*ptr);
+#endif


[gcc r15-2314] libstdc++: fix uses of explicit object parameter [PR116038]

2024-07-25 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:1066a95aa33eee2d2bd9c8324f34dedb967f338c

commit r15-2314-g1066a95aa33eee2d2bd9c8324f34dedb967f338c
Author: Patrick Palka 
Date:   Thu Jul 25 09:02:13 2024 -0400

libstdc++: fix uses of explicit object parameter [PR116038]

The type of an implicit object parameter is always the current class.
For an explicit object parameter however, its deduced type can be a
derived class of the current class.  So when combining multiple
implicit-object overloads into a single explicit-object overload we need
to account for this possibility.  For example when accessing a member of
the current class through an explicit object parameter, it may now be a
derived class from which the member is not accessible, as in the below
testcases.

This pitfall is discussed[1] in the deducing this paper.  The general
solution is to cast the explicit object parameter to (a reference to)
the current class rather than e.g. using std::forward which preserves
the deduced type.

This patch corrects the existing problematic uses of explicit object
parameters in the library, all of which forward the parameter via
std::forward, to instead cast the parameter to the current class via
our __like_t alias template.  Note that unlike the paper's like_t,
ours always returns a reference so we can just write

  __like_t(self)

instead of

  (_like_t&&)self

as the paper does.

[1]: https://wg21.link/P0847#name-lookup-within-member-functions (and the
section after that)

PR libstdc++/116038

libstdc++-v3/ChangeLog:

* include/std/functional (_Bind_front::operator()): Use __like_t
instead of std::forward when forwarding __self.
(_Bind_back::operator()): Likewise.
* include/std/ranges (_Partial::operator()): Likewise.
(_Pipe::operator()): Likewise.
* testsuite/20_util/function_objects/bind_back/116038.cc: New test.
* testsuite/20_util/function_objects/bind_front/116038.cc: New test.
* testsuite/std/ranges/adaptors/116038.cc: New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/functional|  4 +--
 libstdc++-v3/include/std/ranges| 11 +---
 .../20_util/function_objects/bind_back/116038.cc   | 27 
 .../20_util/function_objects/bind_front/116038.cc  | 27 
 .../testsuite/std/ranges/adaptors/116038.cc| 29 ++
 5 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 99364286a72e..7788a9637578 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -944,7 +944,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
__like_t<_Self, _BoundArgs>..., 
_CallArgs...>)
{
- return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+ return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(),
 std::forward<_CallArgs>(__call_args)...);
}
 #else
@@ -1072,7 +1072,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
_CallArgs..., __like_t<_Self, 
_BoundArgs>...>)
{
- return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+ return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(),
 std::forward<_CallArgs>(__call_args)...);
}
 
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3f335b95a086..b7c7aa36ddc4 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1033,7 +1033,7 @@ namespace views::__adaptor
return _Adaptor{}(std::forward<_Range>(__r),
  std::forward(__args)...);
  };
- return std::apply(__forwarder, std::forward<_Self>(__self)._M_args);
+ return std::apply(__forwarder, __like_t<_Self, 
_Partial>(__self)._M_args);
}
 #else
   template
@@ -1082,7 +1082,10 @@ namespace views::__adaptor
requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>>
constexpr auto
operator()(this _Self&& __self, _Range&& __r)
-   { return _Adaptor{}(std::forward<_Range>(__r), 
std::forward<_Self>(__self)._M_arg); }
+   {
+ return _Adaptor{}(std::forward<_Range>(__r),
+   __like_t<_Self, _Partial>(__self)._M_arg);
+   }
 #else
   template
requires __adaptor_invocable<_Adaptor, _Range, const _Arg&>
@@ -1185,8 +1188,8 @@ namespace views::__adaptor
constexpr auto
operator()(this _Self&& __self, _Range&& __r)
{

[gcc r14-10546] libstdc++: fix uses of explicit object parameter [PR116038]

2024-08-01 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:59e3934346f4546d7ef4fc82d300644b52bcefb0

commit r14-10546-g59e3934346f4546d7ef4fc82d300644b52bcefb0
Author: Patrick Palka 
Date:   Thu Jul 25 09:02:13 2024 -0400

libstdc++: fix uses of explicit object parameter [PR116038]

The type of an implicit object parameter is always the current class.
For an explicit object parameter however, its deduced type can be a
derived class of the current class.  So when combining multiple
implicit-object overloads into a single explicit-object overload we need
to account for this possibility.  For example when accessing a member of
the current class through an explicit object parameter, it may now be a
derived class from which the member is not accessible, as in the below
testcases.

This pitfall is discussed[1] in the deducing this paper.  The general
solution is to cast the explicit object parameter to (a reference to)
the current class rather than e.g. using std::forward which preserves
the deduced type.

This patch corrects the existing problematic uses of explicit object
parameters in the library, all of which forward the parameter via
std::forward, to instead cast the parameter to the current class via
our __like_t alias template.  Note that unlike the paper's like_t,
ours always returns a reference so we can just write

  __like_t(self)

instead of

  (_like_t&&)self

as the paper does.

[1]: https://wg21.link/P0847#name-lookup-within-member-functions (and the
section after that)

PR libstdc++/116038

libstdc++-v3/ChangeLog:

* include/std/functional (_Bind_front::operator()): Use __like_t
instead of std::forward when forwarding __self.
(_Bind_back::operator()): Likewise.
* include/std/ranges (_Partial::operator()): Likewise.
(_Pipe::operator()): Likewise.
* testsuite/20_util/function_objects/bind_back/116038.cc: New test.
* testsuite/20_util/function_objects/bind_front/116038.cc: New test.
* testsuite/std/ranges/adaptors/116038.cc: New test.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 1066a95aa33eee2d2bd9c8324f34dedb967f338c)

Diff:
---
 libstdc++-v3/include/std/functional|  4 +--
 libstdc++-v3/include/std/ranges| 11 +---
 .../20_util/function_objects/bind_back/116038.cc   | 27 
 .../20_util/function_objects/bind_front/116038.cc  | 27 
 .../testsuite/std/ranges/adaptors/116038.cc| 29 ++
 5 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/functional 
b/libstdc++-v3/include/std/functional
index 99364286a72e..7788a9637578 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -944,7 +944,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
__like_t<_Self, _BoundArgs>..., 
_CallArgs...>)
{
- return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+ return _S_call(__like_t<_Self, _Bind_front>(__self), _BoundIndices(),
 std::forward<_CallArgs>(__call_args)...);
}
 #else
@@ -1072,7 +1072,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
noexcept(is_nothrow_invocable_v<__like_t<_Self, _Fd>,
_CallArgs..., __like_t<_Self, 
_BoundArgs>...>)
{
- return _S_call(std::forward<_Self>(__self), _BoundIndices(),
+ return _S_call(__like_t<_Self, _Bind_back>(__self), _BoundIndices(),
 std::forward<_CallArgs>(__call_args)...);
}
 
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376bb..59a251536208 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1032,7 +1032,7 @@ namespace views::__adaptor
return _Adaptor{}(std::forward<_Range>(__r),
  std::forward(__args)...);
  };
- return std::apply(__forwarder, std::forward<_Self>(__self)._M_args);
+ return std::apply(__forwarder, __like_t<_Self, 
_Partial>(__self)._M_args);
}
 #else
   template
@@ -1081,7 +1081,10 @@ namespace views::__adaptor
requires __adaptor_invocable<_Adaptor, _Range, __like_t<_Self, _Arg>>
constexpr auto
operator()(this _Self&& __self, _Range&& __r)
-   { return _Adaptor{}(std::forward<_Range>(__r), 
std::forward<_Self>(__self)._M_arg); }
+   {
+ return _Adaptor{}(std::forward<_Range>(__r),
+   __like_t<_Self, _Partial>(__self)._M_arg);
+   }
 #else
   template
requires __adaptor_invocable<_Adaptor, _Range, const _Arg&>
@@ -1184,8 +1187,8 @@ namespace views::__adaptor
cons

[gcc r15-2707] libstdc++: use concrete return type for std::forward_like

2024-08-03 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:8256d5c0097dff00f9bdf9ee0c9d53bd7cec2802

commit r15-2707-g8256d5c0097dff00f9bdf9ee0c9d53bd7cec2802
Author: Patrick Palka 
Date:   Sat Aug 3 09:05:05 2024 -0400

libstdc++: use concrete return type for std::forward_like

Inspired by https://github.com/llvm/llvm-project/issues/101614 this
inverts the relationship between forward_like and __like_t so that
forward_like is defined in terms of __like_t and with a concrete return
type.  __like_t in turn is defined via partial specializations that
pattern match on the const- and reference-ness of T.

This turns out to be more SFINAE friendly and significantly cheaper
to compile than the previous implementation.

libstdc++-v3/ChangeLog:

* include/bits/move.h (__like_impl): New metafunction.
(__like_t): Redefine in terms of __like_impl.
(forward_like): Redefine in terms of __like_t.
* testsuite/20_util/forward_like/2_neg.cc: Don't expect
error outside the immediate context anymore.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/move.h   | 47 +++---
 .../testsuite/20_util/forward_like/2_neg.cc|  6 +--
 2 files changed, 26 insertions(+), 27 deletions(-)

diff --git a/libstdc++-v3/include/bits/move.h b/libstdc++-v3/include/bits/move.h
index bb200c95964a..8397a01b6323 100644
--- a/libstdc++-v3/include/bits/move.h
+++ b/libstdc++-v3/include/bits/move.h
@@ -88,31 +88,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __glibcxx_forward_like // C++ >= 23
   template
-  [[nodiscard]]
-  constexpr decltype(auto)
-  forward_like(_Up&& __x) noexcept
-  {
-constexpr bool __as_rval = is_rvalue_reference_v<_Tp&&>;
-
-if constexpr (is_const_v>)
-  {
-   using _Up2 = remove_reference_t<_Up>;
-   if constexpr (__as_rval)
- return static_cast(__x);
-   else
- return static_cast(__x);
-  }
-else
-  {
-   if constexpr (__as_rval)
- return static_cast&&>(__x);
-   else
- return static_cast<_Up&>(__x);
-  }
-  }
+  struct __like_impl; // _Tp must be a reference and _Up an lvalue reference
+
+  template
+  struct __like_impl<_Tp&, _Up&>
+  { using type = _Up&; };
+
+  template
+  struct __like_impl
+  { using type = const _Up&; };
+
+  template
+  struct __like_impl<_Tp&&, _Up&>
+  { using type = _Up&&; };
+
+  template
+  struct __like_impl
+  { using type = const _Up&&; };
 
   template
-using __like_t = decltype(std::forward_like<_Tp>(std::declval<_Up>()));
+using __like_t = typename __like_impl<_Tp&&, _Up&>::type;
+
+  template
+  [[nodiscard]]
+  constexpr __like_t<_Tp, _Up>
+  forward_like(_Up&& __x) noexcept
+  { return static_cast<__like_t<_Tp, _Up>>(__x); }
 #endif
 
   /**
diff --git a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc 
b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
index ff835af19151..5dafa419a7ea 100644
--- a/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/forward_like/2_neg.cc
@@ -2,9 +2,7 @@
 
 #include 
 
-auto x1 = std::forward_like(1); // { dg-error "here" }
+auto x1 = std::forward_like(1); // { dg-error "no match" }
 // { dg-error "forming reference to void" "" { target *-*-* } 0 }
-auto x2 = std::forward_like(1); // { dg-error "here" }
+auto x2 = std::forward_like(1); // { dg-error "no match" }
 // { dg-error "forming reference to qualified function" "" { target *-*-* } 0 }
-
-// { dg-prune-output "inconsistent deduction for auto return type" } // 
PR111484


[gcc r15-809] libstdc++: Implement ranges::concat_view from P2542R7

2024-05-23 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:66d2a76dcf625f8dbe43d3c512e9c43f588fdc25

commit r15-809-g66d2a76dcf625f8dbe43d3c512e9c43f588fdc25
Author: Patrick Palka 
Date:   Thu May 23 18:03:56 2024 -0400

libstdc++: Implement ranges::concat_view from P2542R7

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__concat_reference_t): Define
for C++26.
(__detail::__concat_value_t): Likewise.
(__detail::__concat_rvalue_reference_t): Likewise.
(__detail::__concat_indirectly_readable_impl): Likewise.
(__detail::__concat_indirectly_readable): Likewise.
(__detail::__concatable): Likewise.
(__detail::__all_but_last_common): Likewise.
(__detail::__concat_is_random_access): Likewise.
(__detail::__concat_is_bidirectional): Likewise.
(__detail::__last_is_common): Likewise.
(concat_view): Likewise.
(__detail::__concat_view_iter_cat): Likewise.
(concat_view::iterator): Likewise.
(views::__detail::__can_concat_view): Likewise.
(views::_Concat, views::concat): Likewise.
* testsuite/std/ranges/concat/1.cc: New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/version.def |   8 +
 libstdc++-v3/include/bits/version.h   |  10 +
 libstdc++-v3/include/std/ranges   | 580 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc |  74 
 4 files changed, 672 insertions(+)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 5cbc9d1a8d8..683b967d54b 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1805,6 +1805,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_concat;
+  values = {
+v = 202403;
+cxxmin = 26;
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 164ebed4983..4850041c0a3 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2013,4 +2013,14 @@
 #endif /* !defined(__cpp_lib_to_string) && defined(__glibcxx_want_to_string) */
 #undef __glibcxx_want_to_string
 
+#if !defined(__cpp_lib_ranges_concat)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_concat 202403L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
+#   define __cpp_lib_ranges_concat 202403L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_concat) && 
defined(__glibcxx_want_ranges_concat) */
+#undef __glibcxx_want_ranges_concat
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index afce818376b..b1e827c9a72 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -55,6 +55,7 @@
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
 #define __glibcxx_want_ranges_cartesian_product
+#define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
 #define __glibcxx_want_ranges_chunk_by
 #define __glibcxx_want_ranges_enumerate
@@ -9514,6 +9515,585 @@ namespace __detail
 } // namespace ranges
 #endif // __cpp_lib_ranges_to_container
 
+#if __cpp_lib_ranges_concat // C++ >= C++26
+namespace ranges
+{
+  namespace __detail
+  {
+template
+  using __concat_reference_t = 
common_reference_t...>;
+
+template
+  using __concat_value_t = common_type_t...>;
+
+template
+  using __concat_rvalue_reference_t
+   = common_reference_t...>;
+
+template
+  concept __concat_indirectly_readable_impl = requires(const _It __it) {
+   { *__it } -> convertible_to<_Ref>;
+   { ranges::iter_move(__it) } -> convertible_to<_RRef>;
+  };
+
+template
+  concept __concat_indirectly_readable
+   = common_reference_with<__concat_reference_t<_Rs...>&&, 
__concat_value_t<_Rs...>&>
+ && common_reference_with<__concat_reference_t<_Rs...>&&,
+  __concat_rvalue_reference_t<_Rs...>&&>
+ && common_reference_with<__concat_rvalue_reference_t<_Rs...>&&,
+  __concat_value_t<_Rs...> const&>
+ && (__concat_indirectly_readable_impl<__concat_reference_t<_Rs...>,
+   
__concat_rvalue_reference_t<_Rs...>,
+   iterator_t<_Rs>>
+ && ...);
+
+template
+  concept __concatable = requires {
+   typename __concat_reference_t<_Rs...>;
+   typename __concat_value_t<_Rs...>;
+   typename __concat_rvalue_reference_t<_Rs...>;
+  } && __concat_indirectly_readable<_Rs...>;
+
+template
+  struct __all_but_last_common

[gcc r15-4070] libstdc++/ranges: Implement various small LWG issues

2024-10-04 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:20165d0107abd0f839f2519818b904f029f4ae55

commit r15-4070-g20165d0107abd0f839f2519818b904f029f4ae55
Author: Patrick Palka 
Date:   Fri Oct 4 10:01:39 2024 -0400

libstdc++/ranges: Implement various small LWG issues

This implements the following small LWG issues:

  3848. adjacent_view, adjacent_transform_view and slide_view missing base 
accessor
  3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
  3947. Unexpected constraints on adjacent_transform_view::base()
  4001. iota_view should provide empty
  4012. common_view::begin/end are missing the simple-view check
  4013. lazy_split_view::outer-iterator::value_type should not provide 
default constructor
  4035. single_view should provide empty
  4053. Unary call to std::views::repeat does not decay the argument
  4054. Repeating a repeat_view should repeat the view

libstdc++-v3/ChangeLog:

* include/std/ranges (single_view::empty): Define as per LWG 4035.
(iota_view::empty): Define as per LWG 4001.
(lazy_split_view::_OuterIter::value_type): Remove default
constructor and make other constructor private as per LWG 4013.
(common_view::begin): Disable non-const overload for simple
views as per LWG 4012.
(common_view::end): Likewise.
(adjacent_view::base): Define as per LWG 3848.
(adjacent_transform_view::base): Likewise.
(chunk_view::_InnerIter::iter_move): Define as per LWG 3851.
(chunk_view::_InnerIter::itep_swap): Likewise.
(slide_view::base): Define as per LWG 3848.
(repeat_view): Adjust deduction guide as per LWG 4053.
(_Repeat::operator()): Adjust single-parameter overload as per
LWG 4054.
* testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence
of base member function.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise.
* testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example.
* testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of
base member function.
* testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example.
* testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges| 84 +++---
 .../testsuite/std/ranges/adaptors/adjacent/1.cc|  3 +
 .../std/ranges/adaptors/adjacent_transform/1.cc|  3 +
 .../testsuite/std/ranges/adaptors/chunk/1.cc   | 15 
 .../testsuite/std/ranges/adaptors/slide/1.cc   |  3 +
 .../testsuite/std/ranges/iota/iota_view.cc | 12 
 libstdc++-v3/testsuite/std/ranges/repeat/1.cc  | 23 ++
 7 files changed, 135 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 30f45e0a750d..6e6e3b97d82f 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -335,6 +335,12 @@ namespace ranges
   end() const noexcept
   { return data() + 1; }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4035. single_view should provide empty
+  static constexpr bool
+  empty() noexcept
+  { return false; }
+
   static constexpr size_t
   size() noexcept
   { return 1; }
@@ -695,6 +701,12 @@ namespace ranges
   end() const requires same_as<_Winc, _Bound>
   { return _Iterator{_M_bound}; }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4001. iota_view should provide empty
+  constexpr bool
+  empty() const
+  { return _M_value == _M_bound; }
+
   constexpr auto
   size() const
   requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
@@ -3349,14 +3361,17 @@ namespace views::__adaptor
  private:
_OuterIter _M_i = _OuterIter();
 
- public:
-   value_type() = default;
-
+   // _GLIBCXX_RESOLVE_LIB_DEFECTS
+   // 4013. lazy_split_view::outer-iterator::value_type should not
+   // provide default constructor
constexpr explicit
value_type(_OuterIter __i)
  : _M_i(std::move(__i))
{ }
 
+   friend _OuterIter;
+
+ public:
constexpr _InnerIter<_Const>
begin() const
{ return _InnerIter<_Const>{_M_i}; }
@@ -3948,8 +3963,10 @@ namespace views::__adaptor
   base() &&
   { return std::move(_M_base); }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4012. common_view::begin/end are missing the simple-view check
   constexpr auto
-  begin()
+  begin() requires (!__detail::__simple_view<_Vp>)
   {
if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
  return ranges::begin(_M_base);
@@ -3969,7 +3986,7 @@ namespace views::__adapt

[gcc r15-4087] libstdc++: add std::is_virtual_base_of

2024-10-05 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:9fc5b8f956948e069d9b69ceed7316940bc798e2

commit r15-4087-g9fc5b8f956948e069d9b69ceed7316940bc798e2
Author: Giuseppe D'Angelo 
Date:   Mon Jul 29 19:23:54 2024 +0200

libstdc++: add std::is_virtual_base_of

Added by P2985R0 for C++26. This simply exposes the compiler
builtin, and adds the feature-testing macro.

libstdc++-v3/ChangeLog:

* include/bits/version.def: Added the feature-testing macro.
* include/bits/version.h: Regenerated.
* include/std/type_traits: Add support for
std::is_virtual_base_of and std::is_virtual_base_of_v,
implemented in terms of the compiler builtin.
* testsuite/20_util/is_virtual_base_of/value.cc: New test.

Signed-off-by: Giuseppe D'Angelo 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/version.def  |  9 ++
 libstdc++-v3/include/bits/version.h| 10 +++
 libstdc++-v3/include/std/type_traits   | 14 +
 .../testsuite/20_util/is_virtual_base_of/value.cc  | 34 ++
 4 files changed, 67 insertions(+)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index f2e28175b087..477651f358a2 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1807,6 +1807,15 @@ ftms = {
   };
 };
 
+ftms = {
+  name = is_virtual_base_of;
+  values = {
+v = 202406;
+cxxmin = 26;
+extra_cond = "__has_builtin(__builtin_is_virtual_base_of)";
+  };
+};
+
 ftms = {
   name = ranges_concat;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index dcd93fd432da..342ee6b4c7a0 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2000,6 +2000,16 @@
 #endif /* !defined(__cpp_lib_fstream_native_handle) && 
defined(__glibcxx_want_fstream_native_handle) */
 #undef __glibcxx_want_fstream_native_handle
 
+#if !defined(__cpp_lib_is_virtual_base_of)
+# if (__cplusplus >  202302L) && (__has_builtin(__builtin_is_virtual_base_of))
+#  define __glibcxx_is_virtual_base_of 202406L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_is_virtual_base_of)
+#   define __cpp_lib_is_virtual_base_of 202406L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_is_virtual_base_of) && 
defined(__glibcxx_want_is_virtual_base_of) */
+#undef __glibcxx_want_is_virtual_base_of
+
 #if !defined(__cpp_lib_ranges_concat)
 # if (__cplusplus >  202302L)
 #  define __glibcxx_ranges_concat 202403L
diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 6e6778078dcf..17ae2c435b38 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -53,6 +53,7 @@
 #define __glibcxx_want_is_pointer_interconvertible
 #define __glibcxx_want_is_scoped_enum
 #define __glibcxx_want_is_swappable
+#define __glibcxx_want_is_virtual_base_of
 #define __glibcxx_want_logical_traits
 #define __glibcxx_want_reference_from_temporary
 #define __glibcxx_want_remove_cvref
@@ -1541,6 +1542,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 : public __bool_constant<__is_base_of(_Base, _Derived)>
 { };
 
+#ifdef __cpp_lib_is_virtual_base_of // C++ >= 26
+  /// is_virtual_base_of
+  /// @since C++26
+  template
+struct is_virtual_base_of
+: public bool_constant<__builtin_is_virtual_base_of(_Base, _Derived)>
+{ };
+#endif
+
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_convertible)
   template
 struct is_convertible
@@ -3636,6 +3646,10 @@ template 
 #endif
 template 
   inline constexpr bool is_base_of_v = __is_base_of(_Base, _Derived);
+#ifdef __cpp_lib_is_virtual_base_of // C++ >= 26
+template 
+  inline constexpr bool is_virtual_base_of_v = 
__builtin_is_virtual_base_of(_Base, _Derived);
+#endif
 #if _GLIBCXX_USE_BUILTIN_TRAIT(__is_convertible)
 template 
   inline constexpr bool is_convertible_v = __is_convertible(_From, _To);
diff --git a/libstdc++-v3/testsuite/20_util/is_virtual_base_of/value.cc 
b/libstdc++-v3/testsuite/20_util/is_virtual_base_of/value.cc
new file mode 100644
index ..5d83de0683e4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/is_virtual_base_of/value.cc
@@ -0,0 +1,34 @@
+// { dg-do compile { target c++26 } }
+
+#include 
+
+#if !defined(__cpp_lib_is_virtual_base_of) || __cpp_lib_is_virtual_base_of < 
202406L
+#error "__cpp_lib_is_virtual_base_of should have been defined to 202406L or 
more"
+#endif
+
+class B { };
+class X : virtual public B { };
+class Y : virtual public B { };
+class Z : public B { };
+class AA : public X, public Y, public Z { };
+
+template
+constexpr bool test()
+{
+  constexpr bool t1 = std::is_virtual_base_of::value;
+  constexpr bool t2 = std::is_virtual_base_of_v;
+  static_assert(t1 == t2);
+  return t1;
+}
+
+void test01()
+{
+  static_assert(!test());
+  static_assert( test());
+  static_assert( test());
+  static_assert(!test());

[gcc r14-10819] libstdc++/ranges: Implement various small LWG issues

2024-10-21 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:07ee6874963d2f8a787ba48341a5392ee8b6ba56

commit r14-10819-g07ee6874963d2f8a787ba48341a5392ee8b6ba56
Author: Patrick Palka 
Date:   Fri Oct 4 10:01:39 2024 -0400

libstdc++/ranges: Implement various small LWG issues

This implements the following small LWG issues:

  3848. adjacent_view, adjacent_transform_view and slide_view missing base 
accessor
  3851. chunk_view::inner-iterator missing custom iter_move and iter_swap
  3947. Unexpected constraints on adjacent_transform_view::base()
  4001. iota_view should provide empty
  4012. common_view::begin/end are missing the simple-view check
  4013. lazy_split_view::outer-iterator::value_type should not provide 
default constructor
  4035. single_view should provide empty
  4053. Unary call to std::views::repeat does not decay the argument
  4054. Repeating a repeat_view should repeat the view

libstdc++-v3/ChangeLog:

* include/std/ranges (single_view::empty): Define as per LWG 4035.
(iota_view::empty): Define as per LWG 4001.
(lazy_split_view::_OuterIter::value_type): Remove default
constructor and make other constructor private as per LWG 4013.
(common_view::begin): Disable non-const overload for simple
views as per LWG 4012.
(common_view::end): Likewise.
(adjacent_view::base): Define as per LWG 3848.
(adjacent_transform_view::base): Likewise.
(chunk_view::_InnerIter::iter_move): Define as per LWG 3851.
(chunk_view::_InnerIter::itep_swap): Likewise.
(slide_view::base): Define as per LWG 3848.
(repeat_view): Adjust deduction guide as per LWG 4053.
(_Repeat::operator()): Adjust single-parameter overload as per
LWG 4054.
* testsuite/std/ranges/adaptors/adjacent/1.cc: Verify existence
of base member function.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise.
* testsuite/std/ranges/adaptors/chunk/1.cc: Test LWG 3851 example.
* testsuite/std/ranges/adaptors/slide/1.cc: Verify existence of
base member function.
* testsuite/std/ranges/iota/iota_view.cc: Test LWG 4001 example.
* testsuite/std/ranges/repeat/1.cc: Test LWG 4053/4054 examples.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 20165d0107abd0f839f2519818b904f029f4ae55)

Diff:
---
 libstdc++-v3/include/std/ranges| 84 +++---
 .../testsuite/std/ranges/adaptors/adjacent/1.cc|  3 +
 .../std/ranges/adaptors/adjacent_transform/1.cc|  3 +
 .../testsuite/std/ranges/adaptors/chunk/1.cc   | 15 
 .../testsuite/std/ranges/adaptors/slide/1.cc   |  3 +
 .../testsuite/std/ranges/iota/iota_view.cc | 12 
 libstdc++-v3/testsuite/std/ranges/repeat/1.cc  | 23 ++
 7 files changed, 135 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 2c8a8535d396..c94463c83e53 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -331,6 +331,12 @@ namespace ranges
   end() const noexcept
   { return data() + 1; }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4035. single_view should provide empty
+  static constexpr bool
+  empty() noexcept
+  { return false; }
+
   static constexpr size_t
   size() noexcept
   { return 1; }
@@ -691,6 +697,12 @@ namespace ranges
   end() const requires same_as<_Winc, _Bound>
   { return _Iterator{_M_bound}; }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4001. iota_view should provide empty
+  constexpr bool
+  empty() const
+  { return _M_value == _M_bound; }
+
   constexpr auto
   size() const
   requires (same_as<_Winc, _Bound> && __detail::__advanceable<_Winc>)
@@ -3350,14 +3362,17 @@ namespace views::__adaptor
  private:
_OuterIter _M_i = _OuterIter();
 
- public:
-   value_type() = default;
-
+   // _GLIBCXX_RESOLVE_LIB_DEFECTS
+   // 4013. lazy_split_view::outer-iterator::value_type should not
+   // provide default constructor
constexpr explicit
value_type(_OuterIter __i)
  : _M_i(std::move(__i))
{ }
 
+   friend _OuterIter;
+
+ public:
constexpr _InnerIter<_Const>
begin() const
{ return _InnerIter<_Const>{_M_i}; }
@@ -3949,8 +3964,10 @@ namespace views::__adaptor
   base() &&
   { return std::move(_M_base); }
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 4012. common_view::begin/end are missing the simple-view check
   constexpr auto
-  begin()
+  begin() requires (!__detail::__simple_view<_Vp>)
   {
if constexpr (random_access_range<_Vp> && sized_range<_Vp>)
  ret

[gcc r14-10816] libstdc++: Implement P2609R3 changes to the indirect invocability concepts

2024-10-21 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:3795ac860bc6f24d0ef222045dff7b2a6350a8c4

commit r14-10816-g3795ac860bc6f24d0ef222045dff7b2a6350a8c4
Author: Patrick Palka 
Date:   Thu Aug 22 09:24:11 2024 -0400

libstdc++: Implement P2609R3 changes to the indirect invocability concepts

This implements the changes of this C++23 paper as a DR against C++20.

Note that after the later P2538R1 "ADL-proof std::projected" (which we
already implement), we can't use a simple partial specialization to match
specializations of the 'projected' alias template.  So instead we identify
such specializations using a pair of distinguishing member aliases.

libstdc++-v3/ChangeLog:

* include/bits/iterator_concepts.h (__detail::__indirect_value):
Define.
(__indirect_value_t): Define as per P2609R3.
(iter_common_reference_t): Adjust as per P2609R3.
(indirectly_unary_invocable): Likewise.
(indirectly_regular_unary_invocable): Likewise.
(indirect_unary_predicate): Likewise.
(indirect_binary_predicate): Likewise.
(indirect_equivalence_relation): Likewise.
(indirect_strict_weak_order): Likewise.
(__detail::__projected::__type): Define member aliases
__projected_Iter and __projected_Proj providing the
template arguments of the current specialization.
* include/bits/version.def (ranges): Update value.
* include/bits/version.h: Regenerate.
* testsuite/24_iterators/indirect_callable/p2609r3.cc: New test.
* testsuite/std/ranges/version_c++23.cc: Update expected value
of __cpp_lib_ranges macro.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit b552730faf36f1eae1dc6e73ccc93a016dec5401)

Diff:
---
 libstdc++-v3/include/bits/iterator_concepts.h  | 61 --
 libstdc++-v3/include/bits/version.def  |  2 +-
 libstdc++-v3/include/bits/version.h|  4 +-
 .../24_iterators/indirect_callable/p2609r3.cc  | 27 ++
 libstdc++-v3/testsuite/std/ranges/version_c++23.cc |  2 +-
 5 files changed, 77 insertions(+), 19 deletions(-)

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index ce0b8a10f88f..9306b7bd194c 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -552,9 +552,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 concept indirectly_readable
   = __detail::__indirectly_readable_impl>;
 
+  namespace __detail
+  {
+template
+  struct __indirect_value
+  { using type = iter_value_t<_Tp>&; };
+
+// __indirect_value> is defined later.
+  } // namespace __detail
+
+  template
+using __indirect_value_t = typename __detail::__indirect_value<_Tp>::type;
+
   template
 using iter_common_reference_t
-  = common_reference_t, iter_value_t<_Tp>&>;
+  = common_reference_t, __indirect_value_t<_Tp>>;
 
   /// Requirements for writing a value into an iterator's referenced object.
   template
@@ -710,24 +722,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
 concept indirectly_unary_invocable = indirectly_readable<_Iter>
-  && copy_constructible<_Fn> && invocable<_Fn&, iter_value_t<_Iter>&>
+  && copy_constructible<_Fn> && invocable<_Fn&, __indirect_value_t<_Iter>>
   && invocable<_Fn&, iter_reference_t<_Iter>>
   && invocable<_Fn&, iter_common_reference_t<_Iter>>
-  && common_reference_with&>,
+  && common_reference_with>,
   invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
   template
 concept indirectly_regular_unary_invocable = indirectly_readable<_Iter>
   && copy_constructible<_Fn>
-  && regular_invocable<_Fn&, iter_value_t<_Iter>&>
+  && regular_invocable<_Fn&, __indirect_value_t<_Iter>>
   && regular_invocable<_Fn&, iter_reference_t<_Iter>>
   && regular_invocable<_Fn&, iter_common_reference_t<_Iter>>
-  && common_reference_with&>,
+  && common_reference_with>,
   invoke_result_t<_Fn&, iter_reference_t<_Iter>>>;
 
   template
 concept indirect_unary_predicate = indirectly_readable<_Iter>
-  && copy_constructible<_Fn> && predicate<_Fn&, iter_value_t<_Iter>&>
+  && copy_constructible<_Fn> && predicate<_Fn&, __indirect_value_t<_Iter>>
   && predicate<_Fn&, iter_reference_t<_Iter>>
   && predicate<_Fn&, iter_common_reference_t<_Iter>>;
 
@@ -735,9 +747,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 concept indirect_binary_predicate
   = indirectly_readable<_I1> && indirectly_readable<_I2>
   && copy_constructible<_Fn>
-  && predicate<_Fn&, iter_value_t<_I1>&, iter_value_t<_I2>&>
-  && predicate<_Fn&, iter_value_t<_I1>&, iter_reference_t<_I2>>
-  && predicate<_Fn&, iter_reference_t<_I1>, iter_value_t<_I2>&>
+  && predicate<_Fn&, __indirect_value_t

[gcc r14-10818] libstdc++: Add some missing ranges feature-test macro tests

2024-10-21 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:be56fee60a62014709605af19a84a48b7aa0835a

commit r14-10818-gbe56fee60a62014709605af19a84a48b7aa0835a
Author: Patrick Palka 
Date:   Thu Aug 22 11:25:10 2024 -0400

libstdc++: Add some missing ranges feature-test macro tests

libstdc++-v3/ChangeLog:

* testsuite/25_algorithms/contains/1.cc: Verify value of
__cpp_lib_ranges_contains.
* testsuite/25_algorithms/find_last/1.cc: Verify value of
__cpp_lib_ranges_find_last.
* testsuite/25_algorithms/iota/1.cc: Verify value of
__cpp_lib_ranges_iota.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 8e0da56f18b3678beee9d2bae27e08a0e122573a)

Diff:
---
 libstdc++-v3/testsuite/25_algorithms/contains/1.cc  | 4 
 libstdc++-v3/testsuite/25_algorithms/find_last/1.cc | 4 
 libstdc++-v3/testsuite/25_algorithms/iota/1.cc  | 5 +
 3 files changed, 13 insertions(+)

diff --git a/libstdc++-v3/testsuite/25_algorithms/contains/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
index 7d3fa048ef61..b44c06032e8a 100644
--- a/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/contains/1.cc
@@ -4,6 +4,10 @@
 #include 
 #include 
 
+#if __cpp_lib_ranges_contains != 202207L
+# error "Feature-test macro __cpp_lib_ranges_contains has wrong value in 
"
+#endif
+
 namespace ranges = std::ranges;
 
 void
diff --git a/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
index 911e22887d1d..8a40bb1a6b36 100644
--- a/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/find_last/1.cc
@@ -4,6 +4,10 @@
 #include 
 #include 
 
+#if __cpp_lib_ranges_find_last != 202207L
+# error "Feature-test macro __cpp_lib_ranges_find_last has wrong value in 
"
+#endif
+
 namespace ranges = std::ranges;
 
 constexpr bool
diff --git a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc 
b/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
index 61bf418b4dae..ebadeee79a13 100644
--- a/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/iota/1.cc
@@ -1,9 +1,14 @@
 // { dg-do run { target c++23 } }
 
 #include 
+#include 
 #include 
 #include 
 
+#if __cpp_lib_ranges_iota != 202202L
+# error "Feature-test macro __cpp_lib_ranges_iota has wrong value in "
+#endif
+
 namespace ranges = std::ranges;
 
 void


[gcc r15-4086] libstdc++: Implement LWG 3664 changes to ranges::distance

2024-10-05 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:7c0d1e9f2a2f1d41d9eb755c36c871d92638c4b7

commit r15-4086-g7c0d1e9f2a2f1d41d9eb755c36c871d92638c4b7
Author: Patrick Palka 
Date:   Sat Oct 5 13:48:06 2024 -0400

libstdc++: Implement LWG 3664 changes to ranges::distance

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h (__distance_fn::operator()):
Adjust iterator/sentinel overloads as per LWG 3664.
* testsuite/24_iterators/range_operations/distance.cc:
Test LWG 3664 example.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h| 14 +++---
 .../testsuite/24_iterators/range_operations/distance.cc| 11 +++
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index 137c3c98e146..cb2eba1f841a 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -947,7 +947,9 @@ namespace ranges
 
   struct __distance_fn final
   {
-template _Sent>
+// _GLIBCXX_RESOLVE_LIB_DEFECTS
+// 3664. LWG 3392 broke std::ranges::distance(a, a+3)
+template _Sent>
   requires (!sized_sentinel_for<_Sent, _It>)
   constexpr iter_difference_t<_It>
   operator()[[nodiscard]](_It __first, _Sent __last) const
@@ -961,13 +963,11 @@ namespace ranges
return __n;
   }
 
-template _Sent>
+template> _Sent>
   [[nodiscard]]
-  constexpr iter_difference_t<_It>
-  operator()(const _It& __first, const _Sent& __last) const
-  {
-   return __last - __first;
-  }
+  constexpr iter_difference_t>
+  operator()(_It&& __first, _Sent __last) const
+  { return __last - static_cast&>(__first); }
 
 template
   [[nodiscard]]
diff --git a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc 
b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
index 9a1d0c3efe83..336956936c22 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_operations/distance.cc
@@ -144,6 +144,16 @@ test05()
   VERIFY( std::ranges::distance(c4) == 5 );
 }
 
+void
+test06()
+{
+  // LWG 3664 - LWG 3392 broke std::ranges::distance(a, a+3)
+  int a[] = {1, 2, 3};
+  VERIFY( std::ranges::distance(a, a+3) == 3 );
+  VERIFY( std::ranges::distance(a, a) == 0 );
+  VERIFY( std::ranges::distance(a+3, a) == -3 );
+}
+
 int
 main()
 {
@@ -152,4 +162,5 @@ main()
   test03();
   test04();
   test05();
+  test06();
 }


[gcc r15-4555] libstdc++: Implement LWG 4166 changes to concat_view::end()

2024-10-22 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:f191c8301545658543773ba3d0e6f3f0927529e0

commit r15-4555-gf191c8301545658543773ba3d0e6f3f0927529e0
Author: Patrick Palka 
Date:   Tue Oct 22 17:01:59 2024 -0400

libstdc++: Implement LWG 4166 changes to concat_view::end()

This patch proactively implements the proposed resolution for this LWG
issue, which seems straightforward and slated to get approved as-is.

(No _GLIBCXX_RESOLVE_LIB_DEFECTS code comment is added since concat_view
is C++26, so this isn't a defect against a published standard.)

libstdc++-v3/ChangeLog:

* include/std/ranges (concat_view::begin): Add space after
'requires' starting a requires-clause.
(concat_view::end): Likewise.  Refine condition for returning an
iterator rather than default_sentinel as per LWG 4166.
* testsuite/std/ranges/concat/1.cc (test03): Verify LWG 4166
example.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges   | 10 ++
 libstdc++-v3/testsuite/std/ranges/concat/1.cc | 20 
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 9f233729d9c7..cebe10683f91 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9687,7 +9687,7 @@ namespace ranges
 { }
 
 constexpr iterator
-begin() requires(!(__detail::__simple_view<_Vs> && ...))
+begin() requires (!(__detail::__simple_view<_Vs> && ...))
 {
   iterator __it(this, in_place_index<0>, 
ranges::begin(std::get<0>(_M_views)));
   __it.template _M_satisfy<0>();
@@ -9703,9 +9703,10 @@ namespace ranges
 }
 
 constexpr auto
-end() requires(!(__detail::__simple_view<_Vs> && ...))
+end() requires (!(__detail::__simple_view<_Vs> && ...))
 {
-  if constexpr (__detail::__last_is_common<_Vs...>::value)
+  if constexpr ((semiregular> && ...)
+   && __detail::__last_is_common<_Vs...>::value)
{
  constexpr auto __n = sizeof...(_Vs);
  return iterator(this, in_place_index<__n - 1>,
@@ -9718,7 +9719,8 @@ namespace ranges
 constexpr auto
 end() const requires (range && ...) && 
__detail::__concatable
 {
-  if constexpr (__detail::__last_is_common::value)
+  if constexpr ((semiregular> && ...)
+   && __detail::__last_is_common::value)
{
  constexpr auto __n = sizeof...(_Vs);
  return iterator(this, in_place_index<__n - 1>,
diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc 
b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
index 6ffe28ece511..e5d10f476e93 100644
--- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -66,9 +67,28 @@ test02()
   VERIFY( ranges::equal(v | views::drop(1), x) );
 }
 
+void
+test03()
+{
+  // LWG 4166 - concat_view::end() should be more constrained in order to
+  // support noncopyable iterators
+  auto range_copyable_it = std::vector{1, 2, 3};
+
+  std::stringstream ss{"4 5 6"};
+  auto range_noncopyable_it = views::istream(ss);
+  ranges::range auto view1 = views::concat(range_copyable_it, 
range_noncopyable_it);
+  VERIFY( ranges::equal(view1, std::vector{1, 2, 3, 4, 5, 6}) );
+
+  ss = std::stringstream{"4 5 6"};
+  range_noncopyable_it = views::istream(ss);
+  ranges::range auto view2 = views::concat(range_noncopyable_it, 
range_copyable_it);
+  VERIFY( ranges::equal(view2, std::vector{4, 5, 6, 1, 2, 3}) );
+}
+
 int
 main()
 {
   static_assert(test01());
   test02();
+  test03();
 }


[gcc r15-4740] libstdc++: Fix complexity of drop_view::begin() const [PR112641]

2024-10-29 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:7f622ee83fbbcf4a4ca70e020db8a0ce4b556b61

commit r15-4740-g7f622ee83fbbcf4a4ca70e020db8a0ce4b556b61
Author: Patrick Palka 
Date:   Tue Oct 29 09:26:19 2024 -0400

libstdc++: Fix complexity of drop_view::begin() const [PR112641]

Views are required to have a amortized O(1) begin(), but our drop_view's
const begin overload is O(n) for non-common ranges with a non-sized
sentinel.  This patch reimplements it so that it's O(1) always.  See
also LWG 4009.

PR libstdc++/112641

libstdc++-v3/ChangeLog:

* include/std/ranges (drop_view::begin): Reimplement const
overload so that it's O(1) always.
* testsuite/std/ranges/adaptors/drop.cc (test10): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges|  4 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc | 12 
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index cebe10683f91..743429dbceae 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -2664,8 +2664,8 @@ namespace views::__adaptor
   begin() const
requires random_access_range && sized_range
   {
-   return ranges::next(ranges::begin(_M_base), _M_count,
-   ranges::end(_M_base));
+   return ranges::begin(_M_base) + ranges::min(ranges::distance(_M_base),
+   _M_count);
   }
 
   constexpr auto
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
index c9987c61e3c1..0bd5bebb785d 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc
@@ -274,6 +274,17 @@ test09()
   static_assert(!requires { views::all | drop; });
 }
 
+constexpr bool
+test10()
+{
+  // PR libstdc++/112641 - drop_view::begin const may have O(n) complexity
+  const auto s = ranges::subrange(views::iota(size_t(1)), size_t(-1));
+  const auto r = ranges::drop_view(s, s.size() - 1);
+  const auto b = r.begin(); // time out
+  VERIFY( *b == size_t(-1) );
+  return true;
+}
+
 int
 main()
 {
@@ -286,4 +297,5 @@ main()
   test07();
   test08();
   test09();
+  static_assert(test10());
 }


[gcc r15-5729] libstdc++/ranges: make _RangeAdaptorClosure befriend operator|

2024-11-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:56029c91dcadcfd1800614b7484d3dc82ca16dde

commit r15-5729-g56029c91dcadcfd1800614b7484d3dc82ca16dde
Author: Patrick Palka 
Date:   Wed Nov 27 11:59:38 2024 -0500

libstdc++/ranges: make _RangeAdaptorClosure befriend operator|

This declares the range adaptor pipe operators a friend of the
_RangeAdaptorClosure base class so that the std module doesn't need to
export them for ADL to find them.

Note that we deliberately don't define these pipe operators as hidden
friends, see r14-3293-g4a6f3676e7dd9e.

libstdc++-v3/ChangeLog:

* include/std/ranges (views::__adaptor::_RangeAdaptorClosure):
Befriend both operator| overloads.
* src/c++23/std.cc.in: Don't export views::__adaptor::operator|.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges  | 23 +--
 libstdc++-v3/src/c++23/std.cc.in |  6 --
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 5153dcc26c4f..f4b897784797 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -949,8 +949,7 @@ namespace views::__adaptor
   // _S_has_simple_call_op to true if the behavior of this adaptor is
   // independent of the constness/value category of the adaptor object.
   template
-struct _RangeAdaptorClosure
-{ };
+struct _RangeAdaptorClosure;
 
   template
 requires (!same_as<_Tp, _RangeAdaptorClosure<_Up>>)
@@ -984,6 +983,26 @@ namespace views::__adaptor
 }
 #pragma GCC diagnostic pop
 
+  template
+struct _RangeAdaptorClosure
+{
+  // In non-modules compilation ADL finds these operators either way and
+  // the friend declarations are redundant.  But with the std module these
+  // friend declarations enable ADL to find these operators without having
+  // to export them.
+  template
+   requires __is_range_adaptor_closure<_Self>
+ && __adaptor_invocable<_Self, _Range>
+   friend constexpr auto
+   operator|(_Range&& __r, _Self&& __self);
+
+  template
+   requires __is_range_adaptor_closure<_Lhs>
+ && __is_range_adaptor_closure<_Rhs>
+   friend constexpr auto
+   operator|(_Lhs&& __lhs, _Rhs&& __rhs);
+};
+
   // The base class of every range adaptor non-closure.
   //
   // The static data member _Derived::_S_arity must contain the total number of
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index 7d787a5f..16e66c3d9210 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -2366,12 +2366,6 @@ export namespace std
 using ranges::concat_view;
 namespace views { using views::concat; }
 #endif
-
-// FIXME can we avoid this export using friends?
-namespace views::__adaptor
-{
-  using __adaptor::operator|;
-}
   }
 }


[gcc r15-5290] libstdc++: Implement LWG 3563 changes to keys_view and values_view

2024-11-14 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:361050589b144913ec05d9d8e10639afa98319a8

commit r15-5290-g361050589b144913ec05d9d8e10639afa98319a8
Author: Patrick Palka 
Date:   Thu Nov 14 13:27:41 2024 -0500

libstdc++: Implement LWG 3563 changes to keys_view and values_view

This LWG issue corrects the definition of these alias templates to make
them suitable for alias CTAD.

libstdc++-v3/ChangeLog:

* include/std/ranges (keys_view): Adjust as per LWG 3563.
(values_view): Likewise.
* testsuite/std/ranges/adaptors/elements.cc (test08): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges|  6 --
 libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc | 14 ++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 743429dbceae..5153dcc26c4f 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -4551,11 +4551,13 @@ namespace views::__adaptor
 inline constexpr bool enable_borrowed_range>
   = enable_borrowed_range<_Tp>;
 
+  // _GLIBCXX_RESOLVE_LIB_DEFECTS
+  // 3563. keys_view example is broken
   template
-using keys_view = elements_view, 0>;
+using keys_view = elements_view<_Range, 0>;
 
   template
-using values_view = elements_view, 1>;
+using values_view = elements_view<_Range, 1>;
 
   namespace views
   {
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
index a15192bf0ecf..0a05ce7378f9 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
@@ -148,6 +148,19 @@ test07()
   b == e;
 }
 
+void
+test08()
+{
+  // LWG 3563 - keys_view example is broken
+  std::pair x[] = {{1,2},{3,4}};
+  auto v = ranges::keys_view{views::all(x)};
+  auto w = ranges::values_view{views::all(x)};
+  using ty1 = decltype(v);
+  using ty1 = ranges::elements_view, 0>;
+  using ty2 = decltype(w);
+  using ty2 = ranges::elements_view, 1>;
+}
+
 int
 main()
 {
@@ -158,4 +171,5 @@ main()
   test05();
   test06();
   test07();
+  test08();
 }


[gcc r14-11259] libstdc++: Fix views::transform(move_only_fn{}) forwarding [PR118413]

2025-01-29 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:f0420cc224db64efe87cbe2f45d4d7ba8deb9eb0

commit r14-11259-gf0420cc224db64efe87cbe2f45d4d7ba8deb9eb0
Author: Patrick Palka 
Date:   Wed Jan 29 10:02:28 2025 -0500

libstdc++: Fix views::transform(move_only_fn{}) forwarding [PR118413]

The range adaptor perfect forwarding simplification mechanism is currently
only enabled for trivially copyable bound arguments, to prevent undesirable
copies of complex objects.  But "trivially copyable" is the wrong property
to check for here, since a move-only type with a trivial move constructor
is considered trivially copyable, and after P2492R2 we can't assume copy
constructibility of the bound arguments.  This patch makes the mechanism
more specifically check for trivial copy constructibility instead so
that it's properly disabled for move-only bound arguments.

PR libstdc++/118413

libstdc++-v3/ChangeLog:

* include/std/ranges (views::__adaptor::_Partial): Adjust
constraints on the "simple" partial specializations to require
is_trivially_copy_constructible_v instead of
is_trivially_copyable_v.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc (test04):
Extend P2494R2 test.
* testsuite/std/ranges/adaptors/transform.cc (test09): Likewise.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 09d1cbee10b8c51aed48f047f30717f622d6f811)

Diff:
---
 libstdc++-v3/include/std/ranges| 4 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc | 1 +
 libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc| 2 ++
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index eba539176848..a966699479bb 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -1122,7 +1122,7 @@ namespace views::__adaptor
   // which makes overload resolution failure diagnostics more concise.
   template
 requires __adaptor_has_simple_extra_args<_Adaptor, _Args...>
-  && (is_trivially_copyable_v<_Args> && ...)
+  && (is_trivially_copy_constructible_v<_Args> && ...)
 struct _Partial<_Adaptor, _Args...> : 
_RangeAdaptorClosure<_Partial<_Adaptor, _Args...>>
 {
   tuple<_Args...> _M_args;
@@ -1153,7 +1153,7 @@ namespace views::__adaptor
   // where _Adaptor accepts a single extra argument.
   template
 requires __adaptor_has_simple_extra_args<_Adaptor, _Arg>
-  && is_trivially_copyable_v<_Arg>
+  && is_trivially_copy_constructible_v<_Arg>
 struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure<_Partial<_Adaptor, 
_Arg>>
 {
   _Arg _M_arg;
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
index a5791b3da702..772e4b3b6a0d 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -110,6 +110,7 @@ test04()
   };
   // P2494R2 Relaxing range adaptors to allow for move only types
   static_assert( requires { views::pairwise_transform(x, move_only{}); } );
+  static_assert( requires { x | views::pairwise_transform(move_only{}); } );
 }
 
 int
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
index e1b74353e632..783b0fba7e1e 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc
@@ -191,8 +191,10 @@ test09()
 #if __cpp_lib_ranges >= 202207L
   // P2494R2 Relaxing range adaptors to allow for move only types
   static_assert( requires { transform(x, move_only{}); } );
+  static_assert( requires { x | transform(move_only{}); } ); // PR 
libstdc++/118413
 #else
   static_assert( ! requires { transform(x, move_only{}); } );
+  static_assert( ! requires { x | transform(move_only{}); } );
 #endif
 }


[gcc r15-7310] libstdc++: Fix flat_foo::insert_range for non-common ranges [PR118156]

2025-01-31 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:a9172b107a24b244e0b71c2575dd6448d48b3ae3

commit r15-7310-ga9172b107a24b244e0b71c2575dd6448d48b3ae3
Author: Patrick Palka 
Date:   Fri Jan 31 15:53:12 2025 -0500

libstdc++: Fix flat_foo::insert_range for non-common ranges [PR118156]

This fixes flat_map/multimap::insert_range by just generalizing the
insert implementation to handle heterogenous iterator/sentinel pair.
I'm not sure we can do better than this, e.g. we can't implement it in
terms of the adapted containers' insert_range because that'd require two
passes over the range.

For flat_set/multiset, we can implement insert_range directly in terms
of the adapted container's insert_range.  A fallback implementation
is also provided if insert_range isn't available, as is the case for
std::deque currently.

PR libstdc++/118156

libstdc++-v3/ChangeLog:

* include/std/flat_map (_Flat_map_impl::_M_insert): Generalized
version of insert taking heterogenous iterator/sentinel pair.
(_Flat_map_impl::insert): Dispatch to _M_insert.
(_Flat_map_impl::insert_range): Likewise.
(flat_map): Export _Flat_map_impl::insert_range.
(flat_multimap): Likewise.
* include/std/flat_set (_Flat_set_impl::insert_range):
Reimplement directly, not in terms of insert.
(flat_set): Export _Flat_set_impl::insert_range.
(flat_multiset): Likewise.
* testsuite/23_containers/flat_map/1.cc (test06): New test.
* testsuite/23_containers/flat_multimap/1.cc (test06): New test.
* testsuite/23_containers/flat_multiset/1.cc (test06): New test.
* testsuite/23_containers/flat_set/1.cc (test06): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/flat_map  | 17 ++
 libstdc++-v3/include/std/flat_set  | 27 +++---
 libstdc++-v3/testsuite/23_containers/flat_map/1.cc | 17 ++
 .../testsuite/23_containers/flat_multimap/1.cc | 16 +
 .../testsuite/23_containers/flat_multiset/1.cc | 16 +
 libstdc++-v3/testsuite/23_containers/flat_set/1.cc | 16 +
 6 files changed, 101 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/std/flat_map 
b/libstdc++-v3/include/std/flat_map
index 1ecc2e7f6e7e..405caa8a81bf 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -538,9 +538,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
insert(const_iterator __position, _Arg&& __x)
{ return emplace_hint(__position, std::forward<_Arg>(__x)); }
 
-  template<__has_input_iter_cat _InputIterator>
+private:
+  template
void
-   insert(_InputIterator __first, _InputIterator __last)
+   _M_insert(_Iter __first, _Sent __last)
{
  // FIXME: This implementation fails its complexity requirements.
  // We can't idiomatically implement an efficient version (as in the
@@ -574,6 +575,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #endif
}
 
+public:
+  template<__has_input_iter_cat _InputIterator>
+   void
+   insert(_InputIterator __first, _InputIterator __last)
+   { _M_insert(std::move(__first), std::move(__last)); }
+
   template<__has_input_iter_cat _InputIterator>
void
insert(__sorted_t, _InputIterator __first, _InputIterator __last)
@@ -585,7 +592,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<__detail::__container_compatible_range _Rg>
void
insert_range(_Rg&& __rg)
-   { insert(ranges::begin(__rg), ranges::end(__rg)); }
+   { _M_insert(ranges::begin(__rg), ranges::end(__rg)); }
 
   void
   insert(initializer_list __il)
@@ -1181,7 +1188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using _Impl::emplace;
   using _Impl::emplace_hint;
   using _Impl::insert;
-  // using _Impl::insert_range;
+  using _Impl::insert_range;
   using _Impl::extract;
   using _Impl::replace;
   using _Impl::erase;
@@ -1460,7 +1467,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using _Impl::emplace;
   using _Impl::emplace_hint;
   using _Impl::insert;
-  // using _Impl::insert_range;
+  using _Impl::insert_range;
   using _Impl::extract;
   using _Impl::replace;
   using _Impl::erase;
diff --git a/libstdc++-v3/include/std/flat_set 
b/libstdc++-v3/include/std/flat_set
index 3e1347a6a0ae..9240f2b9a2eb 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -475,7 +475,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template<__detail::__container_compatible_range _Rg>
void
insert_range(_Rg&& __rg)
-   { insert(ranges::begin(__rg), ranges::end(__rg)); }
+   {
+ auto __guard = _M_make_clear_guard();
+ typename container_type::iterator __it;
+ if con

[gcc r15-7309] libstdc++: Fix return value of vector::insert_range

2025-01-31 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:ee797739606ce9b8cf6ebb0236977861e49aa0d1

commit r15-7309-gee797739606ce9b8cf6ebb0236977861e49aa0d1
Author: Patrick Palka 
Date:   Fri Jan 31 15:53:10 2025 -0500

libstdc++: Fix return value of vector::insert_range

In some cases we're wrongly returning an iterator to (one past) the last
element inserted instead of to the first element inserted.

libstdc++-v3/ChangeLog:

* include/bits/stl_bvector.h (vector::insert_range):
Consistently return an iterator pointing to the first element
inserted.
* include/bits/vector.tcc (vector::insert_range): Likewise.
* 
testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc:
Verify insert_range return values.
* testsuite/23_containers/vector/modifiers/insert/insert_range.cc:
Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/stl_bvector.h|  8 
 libstdc++-v3/include/bits/vector.tcc   |  3 ++-
 .../vector/bool/modifiers/insert/insert_range.cc   | 18 --
 .../vector/modifiers/insert/insert_range.cc| 18 --
 4 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_bvector.h 
b/libstdc++-v3/include/bits/stl_bvector.h
index 961e4a252996..2292eec54ad7 100644
--- a/libstdc++-v3/include/bits/stl_bvector.h
+++ b/libstdc++-v3/include/bits/stl_bvector.h
@@ -1341,9 +1341,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
  std::copy_backward(__pos._M_const_cast(), end(),
 this->_M_impl._M_finish
   + difference_type(__n));
- auto __i = ranges::copy(__rg, __pos._M_const_cast()).out;
+ ranges::copy(__rg, __pos._M_const_cast());
  this->_M_impl._M_finish += difference_type(__n);
- return __i;
+ return __pos._M_const_cast();
}
  else
{
@@ -1355,9 +1355,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
  iterator __i = _M_copy_aligned(__begin,
 __pos._M_const_cast(),
 __start);
- __i = ranges::copy(__rg, __i).out;
+ iterator __j = ranges::copy(__rg, __i).out;
  iterator __finish = std::copy(__pos._M_const_cast(),
-   __end, __i);
+   __end, __j);
  this->_M_deallocate();
  this->_M_impl._M_end_of_storage = __q + _S_nword(__len);
  this->_M_impl._M_start = __start;
diff --git a/libstdc++-v3/include/bits/vector.tcc 
b/libstdc++-v3/include/bits/vector.tcc
index 4f4c366080be..acb2f5fca1e7 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -984,8 +984,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
   {
if (__pos == cend())
  {
+   const auto __ins_idx = size();
append_range(std::forward<_Rg>(__rg));
-   return end();
+   return begin() + __ins_idx;
  }
 
if constexpr (ranges::forward_range<_Rg>)
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
 
b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
index 4f4835746ea4..5c65610667d5 100644
--- 
a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
+++ 
b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
@@ -35,16 +35,22 @@ do_test()
   VERIFY( eq(v, a) );
   v.clear();
   v.shrink_to_fit();
-  v.insert_range(v.begin(), Range(a, a+3));
-  v.insert_range(v.end(), Range(a+6, a+9));
-  v.insert_range(v.begin()+3, Range(a+3, a+6));
+  auto it = v.insert_range(v.begin(), Range(a, a+3));
+  VERIFY( it == v.begin() );
+  it = v.insert_range(v.end(), Range(a+6, a+9));
+  VERIFY( it == v.begin()+3 );
+  it = v.insert_range(v.begin()+3, Range(a+3, a+6));
+  VERIFY( it == v.begin()+3 );
   VERIFY( eq(v, a) );
   v.resize(3);
-  v.insert_range(v.begin()+1, Range(a+4, a+9));
-  v.insert_range(v.begin()+1, Range(a+1, a+4));
+  it = v.insert_range(v.begin()+1, Range(a+4, a+9));
+  VERIFY( it == v.begin()+1 );
+  it = v.insert_range(v.begin()+1, Range(a+1, a+4));
+  VERIFY( it == v.begin()+1 );
   v.resize(9);
   VERIFY( eq(v, a) );
-  v.insert_range(v.begin(), Range(a, a));
+  it = v.insert_range(v.begin(), Range(a, a));
+  VERIFY( it == v.begin() );
   VERIFY( eq(v, a) );
 }
 
diff --git 
a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc 
b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_ra

[gcc r15-6370] libstdc++: Define P1206R7 range-key-type and range-mapped-type aliases

2024-12-19 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:fb1f1c763055abea556959b42a2f1d5e548c1452

commit r15-6370-gfb1f1c763055abea556959b42a2f1d5e548c1452
Author: Patrick Palka 
Date:   Thu Dec 19 11:31:06 2024 -0500

libstdc++: Define P1206R7 range-key-type and range-mapped-type aliases

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h (__detail::__range_key_type):
Define as per P1206R7.
(__detail::__range_mapped_type): Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h | 8 
 1 file changed, 8 insertions(+)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index a2c743ff56bc..c8cd4e87b12c 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -1087,6 +1087,14 @@ namespace __detail
 concept __container_compatible_range
   = ranges::input_range<_Rg>
  && convertible_to, _Tp>;
+
+  template
+using __range_key_type
+  = remove_const_t::first_type>;
+
+  template
+using __range_mapped_type
+  = typename ranges::range_value_t<_Range>::second_type;
 }
 /// @endcond
 #endif


[gcc r15-6371] libstdc++: Implement C++23 (P0429R9)

2024-12-19 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:92381894b36b39030e6a264d3da2204b20f08d6c

commit r15-6371-g92381894b36b39030e6a264d3da2204b20f08d6c
Author: Patrick Palka 
Date:   Thu Dec 19 11:31:09 2024 -0500

libstdc++: Implement C++23  (P0429R9)

This implements the C++23 container adaptors std::flat_map and
std::flat_multimap from P0429R9.  The implementation is shared
as much as possible between the two adaptors via a common base
class that's parameterized according to key uniqueness.

libstdc++-v3/ChangeLog:

* include/Makefile.am: Add new header .
* include/Makefile.in: Regenerate.
* include/bits/alloc_traits.h (__not_allocator_like): New concept.
* include/bits/stl_function.h (__transparent_comparator): Likewise.
* include/bits/stl_iterator_base_types.h (__has_input_iter_cat):
Likewise.
* include/bits/uses_allocator.h (__allocator_for): Likewise.
* include/bits/utility.h (sorted_unique_t): Define for C++23.
(sorted_unique): Likewise.
(sorted_equivalent_t): Likewise.
(sorted_equivalent): Likewise.
* include/bits/version.def (flat_map): Define.
* include/bits/version.h: Regenerate.
* include/precompiled/stdc++.h: Include .
* include/std/flat_map: New file.
* src/c++23/std.cc.in: Export .
* testsuite/23_containers/flat_map/1.cc: New test.
* testsuite/23_containers/flat_multimap/1.cc: New test.

Co-authored-by: Jonathan Wakely 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/Makefile.am   |1 +
 libstdc++-v3/include/Makefile.in   |1 +
 libstdc++-v3/include/bits/alloc_traits.h   |3 +
 libstdc++-v3/include/bits/stl_function.h   |6 +
 .../include/bits/stl_iterator_base_types.h |6 +
 libstdc++-v3/include/bits/uses_allocator.h |5 +
 libstdc++-v3/include/bits/utility.h|8 +
 libstdc++-v3/include/bits/version.def  |8 +
 libstdc++-v3/include/bits/version.h|   10 +
 libstdc++-v3/include/precompiled/stdc++.h  |1 +
 libstdc++-v3/include/std/flat_map  | 1570 
 libstdc++-v3/src/c++23/std.cc.in   |   11 +
 libstdc++-v3/testsuite/23_containers/flat_map/1.cc |  178 +++
 .../testsuite/23_containers/flat_multimap/1.cc |  153 ++
 14 files changed, 1961 insertions(+)

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 6efd3cd5f1c8..b606bcd49359 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -70,6 +70,7 @@ std_headers = \
${std_srcdir}/deque \
${std_srcdir}/execution \
${std_srcdir}/filesystem \
+   ${std_srcdir}/flat_map \
${std_srcdir}/format \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 3b5f93ce185d..d277f87905b9 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -426,6 +426,7 @@ std_freestanding = \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/deque \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/execution \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/filesystem \
+@GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/flat_map \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/format \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/forward_list \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/fstream \
diff --git a/libstdc++-v3/include/bits/alloc_traits.h 
b/libstdc++-v3/include/bits/alloc_traits.h
index 76d5646afe57..5d8a952ec1bf 100644
--- a/libstdc++-v3/include/bits/alloc_traits.h
+++ b/libstdc++-v3/include/bits/alloc_traits.h
@@ -957,6 +957,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   typename _Alloc::value_type;
   __a.deallocate(__a.allocate(1u), 1u);
 };
+
+  template
+concept __not_allocator_like = !__allocator_like<_Alloc>;
 #endif
   /// @endcond
 #endif // C++11
diff --git a/libstdc++-v3/include/bits/stl_function.h 
b/libstdc++-v3/include/bits/stl_function.h
index 8c77471fbf54..a472c3d79f3a 100644
--- a/libstdc++-v3/include/bits/stl_function.h
+++ b/libstdc++-v3/include/bits/stl_function.h
@@ -1426,6 +1426,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   template
 using __has_is_transparent_t
   = typename __has_is_transparent<_Func, _SfinaeType>::type;
+
+#if __cpp_concepts
+  template
+concept __transparent_comparator
+  = requires { typename _Func::is_transparent; };
+#endif
 #endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h 
b/libstdc++-v3/include/bits/stl_iterator_base_types.h
index 710e367c9786..a58358e1059b 100644
--- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
+++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
@@ -253,6 +253,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   

[gcc r15-6372] libstdc++: Implement C++23 (P1222R4)

2024-12-19 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:e3fab34506430e78d286d4aaf66c0dec9a28c187

commit r15-6372-ge3fab34506430e78d286d4aaf66c0dec9a28c187
Author: Patrick Palka 
Date:   Thu Dec 19 11:31:19 2024 -0500

libstdc++: Implement C++23  (P1222R4)

This implements the C++23 container adaptors std::flat_set and
std::flat_multiset from P1222R4.  The implementation is essentially
an simpler and pared down version of std::flat_map.

libstdc++-v3/ChangeLog:

* include/Makefile.am: Add new header .
* include/Makefile.in: Regenerate.
* include/bits/version.def (__cpp_flat_set): Define.
* include/bits/version.h: Regenerate
* include/precompiled/stdc++.h: Include .
* include/std/flat_set: New file.
* src/c++23/std.cc.in: Export .
* testsuite/23_containers/flat_multiset/1.cc: New test.
* testsuite/23_containers/flat_set/1.cc: New test.

Co-authored-by: Jonathan Wakely 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/Makefile.am   |1 +
 libstdc++-v3/include/Makefile.in   |1 +
 libstdc++-v3/include/bits/version.def  |8 +
 libstdc++-v3/include/bits/version.h|   10 +
 libstdc++-v3/include/precompiled/stdc++.h  |1 +
 libstdc++-v3/include/std/flat_set  | 1041 
 libstdc++-v3/src/c++23/std.cc.in   |   11 +
 .../testsuite/23_containers/flat_multiset/1.cc |  140 +++
 libstdc++-v3/testsuite/23_containers/flat_set/1.cc |  155 +++
 9 files changed, 1368 insertions(+)

diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index b606bcd49359..3e1e42e79737 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -71,6 +71,7 @@ std_headers = \
${std_srcdir}/execution \
${std_srcdir}/filesystem \
${std_srcdir}/flat_map \
+   ${std_srcdir}/flat_set \
${std_srcdir}/format \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index d277f87905b9..4c461afb7513 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -427,6 +427,7 @@ std_freestanding = \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/execution \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/filesystem \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/flat_map \
+@GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/flat_set \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/format \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/forward_list \
 @GLIBCXX_HOSTED_TRUE@  ${std_srcdir}/fstream \
diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 171ee2780e8d..3b31cff51943 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1671,6 +1671,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = flat_set;
+  values = {
+v = 202207;
+cxxmin = 23;
+  };
+};
+
 ftms = {
   name = formatters;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 5e1858855eb6..ef27ae5e4fae 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -1845,6 +1845,16 @@
 #endif /* !defined(__cpp_lib_flat_map) && defined(__glibcxx_want_flat_map) */
 #undef __glibcxx_want_flat_map
 
+#if !defined(__cpp_lib_flat_set)
+# if (__cplusplus >= 202100L)
+#  define __glibcxx_flat_set 202207L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_flat_set)
+#   define __cpp_lib_flat_set 202207L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_flat_set) && defined(__glibcxx_want_flat_set) */
+#undef __glibcxx_want_flat_set
+
 #if !defined(__cpp_lib_formatters)
 # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED
 #  define __glibcxx_formatters 202302L
diff --git a/libstdc++-v3/include/precompiled/stdc++.h 
b/libstdc++-v3/include/precompiled/stdc++.h
index 67ee00d073bb..3312a7a4dd4d 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -226,6 +226,7 @@
 #if __cplusplus > 202002L
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/libstdc++-v3/include/std/flat_set 
b/libstdc++-v3/include/std/flat_set
new file mode 100644
index ..3e1347a6a0ae
--- /dev/null
+++ b/libstdc++-v3/include/std/flat_set
@@ -0,0 +1,1041 @@
+//  -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// 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 o

[gcc r14-11174] libstdc++: Avoid unnecessary copies in ranges::min/max [PR112349]

2025-01-09 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:f236c897af48c3ae52095a894d57e66065b8ad87

commit r14-11174-gf236c897af48c3ae52095a894d57e66065b8ad87
Author: Patrick Palka 
Date:   Fri Dec 13 13:17:29 2024 -0500

libstdc++: Avoid unnecessary copies in ranges::min/max [PR112349]

Use a local reference for the (now possibly lifetime extended) result of
*__first so that we copy it only when necessary.

PR libstdc++/112349

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__min_fn::operator()): Turn local
object __tmp into a reference.
* include/bits/ranges_util.h (__max_fn::operator()): Likewise.
* testsuite/25_algorithms/max/constrained.cc (test04): New test.
* testsuite/25_algorithms/min/constrained.cc (test04): New test.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit b8314ebff2495ee22f9e2203093bdada9843a0f5)

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h|  4 ++--
 libstdc++-v3/include/bits/ranges_util.h|  4 ++--
 .../testsuite/25_algorithms/max/constrained.cc | 25 ++
 .../testsuite/25_algorithms/min/constrained.cc | 25 ++
 4 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 6347ec98606a..a29d387dc711 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -2909,11 +2909,11 @@ namespace ranges
auto __result = *__first;
while (++__first != __last)
  {
-   auto __tmp = *__first;
+   auto&& __tmp = *__first;
if (std::__invoke(__comp,
  std::__invoke(__proj, __result),
  std::__invoke(__proj, __tmp)))
- __result = std::move(__tmp);
+ __result = std::forward(__tmp);
  }
return __result;
   }
diff --git a/libstdc++-v3/include/bits/ranges_util.h 
b/libstdc++-v3/include/bits/ranges_util.h
index 34d8b1e8f143..aba5b6a88c0c 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -733,11 +733,11 @@ namespace ranges
auto __result = *__first;
while (++__first != __last)
  {
-   auto __tmp = *__first;
+   auto&& __tmp = *__first;
if (std::__invoke(__comp,
  std::__invoke(__proj, __tmp),
  std::__invoke(__proj, __result)))
- __result = std::move(__tmp);
+ __result = std::forward(__tmp);
  }
return __result;
   }
diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
index e7269e1b734a..ad2d47f2f101 100644
--- a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
@@ -73,10 +73,35 @@ test03()
   VERIFY( ranges::max({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 4 );
 }
 
+void
+test04()
+{
+  // PR libstdc++/112349 - ranges::max/min make unnecessary copies
+  static int copies, moves;
+  struct A {
+A(int m) : m(m) { }
+A(const A& other) : m(other.m) { ++copies; }
+A(A&& other) : m(other.m) { ++moves; }
+A& operator=(const A& other) { m = other.m; ++copies; return *this; }
+A& operator=(A&& other) { m = other.m; ++moves; return *this; }
+int m;
+  };
+  A r[5] = {5, 4, 3, 2, 1};
+  ranges::max(r, ranges::less{}, &A::m);
+  VERIFY( copies == 1 );
+  VERIFY( moves == 0 );
+  copies = moves = 0;
+  A s[5] = {1, 2, 3, 4, 5};
+  ranges::max(s, ranges::less{}, &A::m);
+  VERIFY( copies == 5 );
+  VERIFY( moves == 0 );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }
diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
index 7198df69adf7..17048fda6394 100644
--- a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
@@ -73,10 +73,35 @@ test03()
   VERIFY( ranges::min({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 1 );
 }
 
+void
+test04()
+{
+  // PR libstdc++/112349 - ranges::max/min make unnecessary copies
+  static int copies, moves;
+  struct A {
+A(int m) : m(m) { }
+A(const A& other) : m(other.m) { ++copies; }
+A(A&& other) : m(other.m) { ++moves; }
+A& operator=(const A& other) { m = other.m; ++copies; return *this; }
+A& operator=(A&& other) { m = other.m; ++moves; return *this; }
+int m;
+  };
+  A r[5] = {5, 4, 3, 2, 1};
+  ranges::min(r, ranges::less{}, &A::m);
+  VERIFY( copies == 5 );
+  VERIFY( moves == 0 );
+  copies = moves = 0;
+  A s[5] = {1, 2, 3, 4, 5};
+  ranges::min(s, ranges::less{}, &A::m);
+  VERIFY( copies == 1 );
+  VERIFY( moves == 0 );
+}
+
 int
 main()
 {
   test01();
   test02();
 

[gcc r15-7066] libstdc++: perfectly forward std::ranges::clamp arguments

2025-01-20 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:b342614139c0a981b369176980663941b9c27f39

commit r15-7066-gb342614139c0a981b369176980663941b9c27f39
Author: Giuseppe D'Angelo 
Date:   Sun Jan 19 16:30:20 2025 +0100

libstdc++: perfectly forward std::ranges::clamp arguments

As reported in PR118185, std::ranges::clamp does not correctly forward
the projected value to the comparator. Add the missing forward.

libstdc++-v3/ChangeLog:

PR libstdc++/118185
PR libstdc++/100249
* include/bits/ranges_algo.h (__clamp_fn): Correctly forward the
projected value to the comparator.
* testsuite/25_algorithms/clamp/118185.cc: New test.

Signed-off-by: Giuseppe D'Angelo 
Reviewed-by: Patrick Palka 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h|  8 +++--
 .../testsuite/25_algorithms/clamp/118185.cc| 41 ++
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 380f05f1e296..df92598f51a1 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -2988,9 +2988,13 @@ namespace ranges
 std::__invoke(__proj, __hi),
 std::__invoke(__proj, __lo;
auto&& __proj_val = std::__invoke(__proj, __val);
-   if (std::__invoke(__comp, __proj_val, std::__invoke(__proj, __lo)))
+   if (std::__invoke(__comp,
+ std::forward(__proj_val),
+ std::__invoke(__proj, __lo)))
  return __lo;
-   else if (std::__invoke(__comp, std::__invoke(__proj, __hi), __proj_val))
+   else if (std::__invoke(__comp,
+  std::__invoke(__proj, __hi),
+  std::forward(__proj_val)))
  return __hi;
else
  return __val;
diff --git a/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc 
b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc
new file mode 100644
index ..e9cf896d3556
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++20 } }
+
+#include 
+#include 
+
+struct Comp
+{
+  constexpr bool operator()(const int&& x, const int&& y) { return x < y; }
+};
+
+struct Proj
+{
+  constexpr const int&& operator()(const int& x) const { return std::move(x); }
+};
+
+static_assert(std::indirect_strict_weak_order>);
+
+static_assert(std::ranges::clamp(+1, 0, 2, Comp{}, Proj{}) == 1);
+static_assert(std::ranges::clamp(-1, 0, 2, Comp{}, Proj{}) == 0);
+static_assert(std::ranges::clamp(10, 0, 2, Comp{}, Proj{}) == 2);
+
+
+// Testcase from PR118185
+
+struct Comp2
+{
+  constexpr bool operator()(const int&& x, const int&& y) const { return x < 
y; }
+  constexpr bool operator()(const int&& x, int& y) const { return x < y; }
+  constexpr bool operator()(int& x, const int&& y) const { return x < y; }
+  constexpr bool operator()(int& x, int& y) const { return x < y; }
+  constexpr bool operator()(std::same_as auto && x, 
std::same_as auto && y) const
+  {
+return x < y;
+  }
+};
+
+static_assert(std::indirect_strict_weak_order>);
+
+static_assert(std::ranges::clamp(+1, 0, 2, Comp2{}, Proj{}) == 1);
+static_assert(std::ranges::clamp(-1, 0, 2, Comp2{}, Proj{}) == 0);
+static_assert(std::ranges::clamp(10, 0, 2, Comp2{}, Proj{}) == 2);


[gcc r14-11251] libstdc++: perfectly forward std::ranges::clamp arguments

2025-01-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:d121d1e1dd874731a648086772e6c40e34fa5de9

commit r14-11251-gd121d1e1dd874731a648086772e6c40e34fa5de9
Author: Giuseppe D'Angelo 
Date:   Sun Jan 19 16:30:20 2025 +0100

libstdc++: perfectly forward std::ranges::clamp arguments

As reported in PR118185, std::ranges::clamp does not correctly forward
the projected value to the comparator. Add the missing forward.

libstdc++-v3/ChangeLog:

PR libstdc++/118185
PR libstdc++/100249
* include/bits/ranges_algo.h (__clamp_fn): Correctly forward the
projected value to the comparator.
* testsuite/25_algorithms/clamp/118185.cc: New test.

Signed-off-by: Giuseppe D'Angelo 
Reviewed-by: Patrick Palka 
Reviewed-by: Jonathan Wakely 
(cherry picked from commit b342614139c0a981b369176980663941b9c27f39)

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h|  8 +++--
 .../testsuite/25_algorithms/clamp/118185.cc| 41 ++
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index a29d387dc711..0386e7aafa6d 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -2945,9 +2945,13 @@ namespace ranges
 std::__invoke(__proj, __hi),
 std::__invoke(__proj, __lo;
auto&& __proj_val = std::__invoke(__proj, __val);
-   if (std::__invoke(__comp, __proj_val, std::__invoke(__proj, __lo)))
+   if (std::__invoke(__comp,
+ std::forward(__proj_val),
+ std::__invoke(__proj, __lo)))
  return __lo;
-   else if (std::__invoke(__comp, std::__invoke(__proj, __hi), __proj_val))
+   else if (std::__invoke(__comp,
+  std::__invoke(__proj, __hi),
+  std::forward(__proj_val)))
  return __hi;
else
  return __val;
diff --git a/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc 
b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc
new file mode 100644
index ..e9cf896d3556
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/clamp/118185.cc
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++20 } }
+
+#include 
+#include 
+
+struct Comp
+{
+  constexpr bool operator()(const int&& x, const int&& y) { return x < y; }
+};
+
+struct Proj
+{
+  constexpr const int&& operator()(const int& x) const { return std::move(x); }
+};
+
+static_assert(std::indirect_strict_weak_order>);
+
+static_assert(std::ranges::clamp(+1, 0, 2, Comp{}, Proj{}) == 1);
+static_assert(std::ranges::clamp(-1, 0, 2, Comp{}, Proj{}) == 0);
+static_assert(std::ranges::clamp(10, 0, 2, Comp{}, Proj{}) == 2);
+
+
+// Testcase from PR118185
+
+struct Comp2
+{
+  constexpr bool operator()(const int&& x, const int&& y) const { return x < 
y; }
+  constexpr bool operator()(const int&& x, int& y) const { return x < y; }
+  constexpr bool operator()(int& x, const int&& y) const { return x < y; }
+  constexpr bool operator()(int& x, int& y) const { return x < y; }
+  constexpr bool operator()(std::same_as auto && x, 
std::same_as auto && y) const
+  {
+return x < y;
+  }
+};
+
+static_assert(std::indirect_strict_weak_order>);
+
+static_assert(std::ranges::clamp(+1, 0, 2, Comp2{}, Proj{}) == 1);
+static_assert(std::ranges::clamp(-1, 0, 2, Comp2{}, Proj{}) == 0);
+static_assert(std::ranges::clamp(10, 0, 2, Comp2{}, Proj{}) == 2);


[gcc r14-11446] libstdc++: Fix ref_view branch of views::as_const [PR119135]

2025-04-05 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:925a744efec5a630eb9bf49e755c554a884fda99

commit r14-11446-g925a744efec5a630eb9bf49e755c554a884fda99
Author: Patrick Palka 
Date:   Thu Mar 13 09:15:21 2025 -0400

libstdc++: Fix ref_view branch of views::as_const [PR119135]

Unlike for span and empty_view, the range_reference_t of
ref_view doesn't correspond to X.  This patch fixes the ref_view
branch of views::as_const to correctly query its underlying range
type X.

PR libstdc++/119135

libstdc++-v3/ChangeLog:

* include/std/ranges: Include .
(views::__detail::__is_ref_view): Replace with ...
(views::__detail::__is_constable_ref_view): ... this.
(views::_AsConst::operator()): Replace bogus use of element_type
in the ref_view branch.
* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 
(cherry picked from commit 50359c0a44381edb6dbd9359ef2ebdadbcc3ed42)

Diff:
---
 libstdc++-v3/include/std/ranges  | 12 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc |  4 
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index a966699479bb..c2dcb0265660 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -46,6 +46,7 @@
 #include 
 #include 
 #if __cplusplus > 202002L
+#include 
 #include 
 #endif
 #include 
@@ -9297,10 +9298,11 @@ namespace views::__adaptor
 namespace __detail
 {
   template
-   inline constexpr bool __is_ref_view = false;
+   inline constexpr bool __is_constable_ref_view = false;
 
   template
-   inline constexpr bool __is_ref_view> = true;
+   inline constexpr bool __is_constable_ref_view>
+ = constant_range;
 
   template
concept __can_as_const_view = requires { 
as_const_view(std::declval<_Range>()); };
@@ -9322,10 +9324,8 @@ namespace views::__adaptor
  return views::empty;
else if constexpr (std::__detail::__is_span<_Tp>)
  return span(std::forward<_Range>(__r));
-   else if constexpr (__detail::__is_ref_view<_Tp>
-  && constant_range)
- return ref_view(static_cast
- (std::forward<_Range>(__r).base()));
+   else if constexpr (__detail::__is_constable_ref_view<_Tp>)
+ return ref_view(std::as_const(std::forward<_Range>(__r).base()));
else if constexpr (is_lvalue_reference_v<_Range>
   && constant_range
   && !view<_Tp>)
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index c36786a8c5fa..3f1f8eb17726 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -63,6 +63,10 @@ test03()
   std::vector v;
   std::same_as>>
 auto r = views::as_const(v);
+
+  // PR libstdc++/119135
+  std::same_as>>
+auto r2 = views::as_const(views::all(v));
 }
 
 int


[gcc r14-11536] libstdc++: Work around C++20 tuple> constraint recursion [PR116440]

2025-04-07 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:5cdf31f08074d5ed8d07e93390de573938ad1eb3

commit r14-11536-g5cdf31f08074d5ed8d07e93390de573938ad1eb3
Author: Patrick Palka 
Date:   Thu Mar 13 19:55:00 2025 -0400

libstdc++: Work around C++20 tuple> constraint recursion 
[PR116440]

The type tuple> is clearly copy/move constructible, but for
reasons that are not yet completely understood checking this triggers
constraint recursion with our C++20 tuple implementation (but not the
C++17 implementation).

It turns out this recursion stems from considering the non-template
tuple(const _Elements&) constructor during the copy/move constructibility
check.  Considering this constructor is ultimately redundant, since the
defaulted copy/move constructors are better matches.

GCC has a non-standard "perfect candidate" optimization[1] that causes
overload resolution to shortcut considering template candidates if we
find a (non-template) perfect candidate.  So to work around this issue
(and as a general compile-time optimization) this patch turns the
problematic constructor into a template so that GCC doesn't consider it
when checking for copy/move constructibility of this tuple type.

Changing the template-ness of a constructor can affect overload
resolution (since template-ness is a tiebreaker) so there's a risk this
change could e.g. introduce overload resolution ambiguities.  But the
original C++17 implementation has long defined this constructor as a
template (in order to constrain it etc), so doing the same thing in the
C++20 mode should naturally be quite safe.

The testcase still fails with Clang (in C++20 mode) since it doesn't
implement said optimization.

[1]: See r11-7287-g187d0d5871b1fa and
https://isocpp.org/files/papers/P3606R0.html

PR libstdc++/116440

libstdc++-v3/ChangeLog:

* include/std/tuple (tuple::tuple(const _Elements&...))
[C++20]: Turn into a template.
* testsuite/20_util/tuple/116440.C: New test.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 6570fa6f2612a4e4ddd2fcfc119369a1a48656e4)

Diff:
---
 libstdc++-v3/include/std/tuple| 14 +++--
 libstdc++-v3/testsuite/20_util/tuple/116440.C | 29 +++
 2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple
index 85a380842b6e..c46665056818 100644
--- a/libstdc++-v3/include/std/tuple
+++ b/libstdc++-v3/include/std/tuple
@@ -969,12 +969,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   : _Inherited()
   { }
 
-  constexpr explicit(!__convertible())
-  tuple(const _Elements&... __elements)
-  noexcept(__nothrow_constructible())
-  requires (__constructible())
-  : _Inherited(__elements...)
-  { }
+  // Defined as a template to work around PR libstdc++/116440.
+  template
+   constexpr explicit(!__convertible())
+   tuple(const _Elements&... __elements)
+   noexcept(__nothrow_constructible())
+   requires (__constructible())
+   : _Inherited(__elements...)
+   { }
 
   template
requires (__disambiguating_constraint<_UTypes...>())
diff --git a/libstdc++-v3/testsuite/20_util/tuple/116440.C 
b/libstdc++-v3/testsuite/20_util/tuple/116440.C
new file mode 100644
index ..12259134d251
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/tuple/116440.C
@@ -0,0 +1,29 @@
+// PR libstdc++/116440 - std::tuple> does not compile
+// { dg-do compile { target c++17 } }
+
+#include 
+#include 
+#include 
+
+template 
+using TupleTuple = std::tuple>;
+
+struct EmbedAny {
+std::any content;
+};
+
+static_assert(std::is_copy_constructible>::value);
+static_assert(std::is_move_constructible>::value);
+
+static_assert(std::is_copy_constructible>::value);
+static_assert(std::is_move_constructible>::value);
+
+static_assert(std::is_constructible_v>);
+
+struct EmbedAnyWithZeroSizeArray {
+void* pad[0];
+std::any content;
+};
+
+static_assert(std::is_copy_constructible>::value);
+static_assert(std::is_move_constructible>::value);


[gcc r14-11578] libstdc++: Fix constraint recursion in basic_const_iterator operator- [PR115046]

2025-04-09 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:630bca9fa83236e108e9421549bdd5058133c3dd

commit r14-11578-g630bca9fa83236e108e9421549bdd5058133c3dd
Author: Patrick Palka 
Date:   Wed Apr 9 17:48:05 2025 -0400

libstdc++: Fix constraint recursion in basic_const_iterator operator- 
[PR115046]

It was proposed in PR112490 to also adjust basic_const_iterator's friend
operator-(sent, iter) overload alongside the r15-7757-g4342c50ca84ae5
adjustments to its comparison operators, but we lacked a concrete
testcase demonstrating fixable constraint recursion there.  It turns out
Hewill Kang's PR115046 is such a testcase!  So this patch makes the same
adjustments to that overload as well, fixing PR115046.  The LWG 4218 P/R
will need to get adjusted too.

PR libstdc++/115046
PR libstdc++/112490

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (basic_const_iterator::operator-):
Replace non-dependent basic_const_iterator function parameter with
a dependent one of type basic_const_iterator<_It2> where _It2
matches _It.
* testsuite/std/ranges/adaptors/as_const/1.cc (test04): New test.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit d69f73c0334486f3c66937388f02008736809e87)

Diff:
---
 libstdc++-v3/include/bits/stl_iterator.h |  4 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc | 13 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 5e1fe30135ef..2162792782eb 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2917,10 +2917,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   noexcept(noexcept(_M_current - __y))
   { return _M_current - __y; }
 
-template<__detail::__not_a_const_iterator _Sent>
+template<__detail::__not_a_const_iterator _Sent, same_as<_It> _It2>
   requires sized_sentinel_for<_Sent, _It>
   friend constexpr difference_type
-  operator-(const _Sent& __x, const basic_const_iterator& __y)
+  operator-(const _Sent& __x, const basic_const_iterator<_It2>& __y)
   noexcept(noexcept(__x - __y._M_current))
   { return __x - __y._M_current; }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index 3f1f8eb17726..5ccf47d4d300 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -69,10 +69,23 @@ test03()
 auto r2 = views::as_const(views::all(v));
 }
 
+void
+test04()
+{
+  // PR libstdc++/115046 - meta-recursion with join_view and as_const_view
+  int x[3] = {1,2,3};
+  auto v = x
+| views::chunk(3)
+| views::transform(views::as_const)
+| views::join;
+  VERIFY( ranges::equal(v, x) );
+}
+
 int
 main()
 {
   static_assert(test01());
   static_assert(test02());
   test03();
+  test04();
 }


[gcc r15-9351] libstdc++: Fix constraint recursion in basic_const_iterator operator- [PR115046]

2025-04-09 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:d69f73c0334486f3c66937388f02008736809e87

commit r15-9351-gd69f73c0334486f3c66937388f02008736809e87
Author: Patrick Palka 
Date:   Wed Apr 9 17:48:05 2025 -0400

libstdc++: Fix constraint recursion in basic_const_iterator operator- 
[PR115046]

It was proposed in PR112490 to also adjust basic_const_iterator's friend
operator-(sent, iter) overload alongside the r15-7757-g4342c50ca84ae5
adjustments to its comparison operators, but we lacked a concrete
testcase demonstrating fixable constraint recursion there.  It turns out
Hewill Kang's PR115046 is such a testcase!  So this patch makes the same
adjustments to that overload as well, fixing PR115046.  The LWG 4218 P/R
will need to get adjusted too.

PR libstdc++/115046
PR libstdc++/112490

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (basic_const_iterator::operator-):
Replace non-dependent basic_const_iterator function parameter with
a dependent one of type basic_const_iterator<_It2> where _It2
matches _It.
* testsuite/std/ranges/adaptors/as_const/1.cc (test04): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/stl_iterator.h |  4 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc | 13 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 33732b1a4287..9203a66b2ff0 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2933,10 +2933,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   noexcept(noexcept(_M_current - __y))
   { return _M_current - __y; }
 
-template<__detail::__not_a_const_iterator _Sent>
+template<__detail::__not_a_const_iterator _Sent, same_as<_It> _It2>
   requires sized_sentinel_for<_Sent, _It>
   friend constexpr difference_type
-  operator-(const _Sent& __x, const basic_const_iterator& __y)
+  operator-(const _Sent& __x, const basic_const_iterator<_It2>& __y)
   noexcept(noexcept(__x - __y._M_current))
   { return __x - __y._M_current; }
 
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index 3f1f8eb17726..5ccf47d4d300 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -69,10 +69,23 @@ test03()
 auto r2 = views::as_const(views::all(v));
 }
 
+void
+test04()
+{
+  // PR libstdc++/115046 - meta-recursion with join_view and as_const_view
+  int x[3] = {1,2,3};
+  auto v = x
+| views::chunk(3)
+| views::transform(views::as_const)
+| views::join;
+  VERIFY( ranges::equal(v, x) );
+}
+
 int
 main()
 {
   static_assert(test01());
   static_assert(test02());
   test03();
+  test04();
 }


[gcc r15-9572] Revert "libstdc++: Optimize std::projected" [PR119888]

2025-04-22 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:63bda370eddf091c456cea3df82e0e5aa9a1fa97

commit r15-9572-g63bda370eddf091c456cea3df82e0e5aa9a1fa97
Author: Patrick Palka 
Date:   Tue Apr 22 12:55:05 2025 -0400

Revert "libstdc++: Optimize std::projected" [PR119888]

This non-standard optimization breaks real-world code that expects the
result of std::projected to always (be a class type and) have a value_type
member, which isn't true for e.g. I=int*, so revert it for now.

PR libstdc++/119888

This reverts commit 51761c50f843d5be4e24172535e4524b5072f24c.

Diff:
---
 libstdc++-v3/include/bits/iterator_concepts.h  | 5 -
 libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc | 5 -
 2 files changed, 10 deletions(-)

diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index e36556dc5121..3b73ff9b6b59 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -829,11 +829,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  using __projected_Proj = _Proj;
};
   };
-
-// Optimize the common case of the projection being std::identity.
-template
-  struct __projected<_Iter, identity>
-  { using __type = _Iter; };
   } // namespace __detail
 
   /// [projected], projected
diff --git a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc 
b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
index 0b18616aa8b7..e2fbf7dccb9c 100644
--- a/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
+++ b/libstdc++-v3/testsuite/24_iterators/indirect_callable/projected.cc
@@ -22,12 +22,7 @@
 template
   using PI = std::projected;
 
-#if __GLIBCXX__
-// Verify our projected optimization.
-static_assert(std::same_as, int*>);
-#else
 static_assert(std::same_as::value_type, int>);
-#endif
 static_assert(std::same_as&>()), int&>);
 
 struct X


[gcc r14-11696] libstdc++: Add code comment documenting LWG 4027 change [PR118083]

2025-04-28 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:d03c58584da3c440cc9103d6a69f6c36f16f6e97

commit r14-11696-gd03c58584da3c440cc9103d6a69f6c36f16f6e97
Author: Patrick Palka 
Date:   Wed Feb 26 14:51:38 2025 -0500

libstdc++: Add code comment documenting LWG 4027 change [PR118083]

PR libstdc++/118083

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h
(ranges::__access::__possibly_const_range): Mention LWG 4027.

(cherry picked from commit 640697f7c2def415db81c84010ae25be0785d867)

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index 481d9bb5c5d5..eafd982f48e2 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -635,6 +635,8 @@ namespace ranges
   constexpr auto&
   __possibly_const_range(_Range& __r) noexcept
   {
+   // _GLIBCXX_RESOLVE_LIB_DEFECTS
+   // 4027. possibly-const-range should prefer returning const R&
if constexpr (input_range)
  return const_cast(__r);
else


[gcc r16-282] libstdc++: Fix availability of std::erase_if(std::flat_foo) [PR119427]

2025-04-29 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:aa93272cfd2233858da0792761387cc27f4d5ff3

commit r16-282-gaa93272cfd2233858da0792761387cc27f4d5ff3
Author: Patrick Palka 
Date:   Tue Apr 29 08:21:35 2025 -0400

libstdc++: Fix availability of std::erase_if(std::flat_foo) [PR119427]

These std::erase_if overloads were wrongly implemented as hidden
friends, visible only via ADL, so erase_if(x) would work but not
std::erase_if(x).

PR libstdc++/119427

libstdc++-v3/ChangeLog:

* include/std/flat_map (_Flat_map_impl::erase_if): Replace
this hidden friend with ...
(_Flat_map_impl::_M_erase_if): ... this member function.
(flat_map): Export _Flat_map_impl::_M_erase_if.
(erase_if(flat_map)): Define.
(flat_multimap): Export _Flat_map_impl::_M_erase_if.
(erase_if(flat_multimap)): Define.
* include/std/flat_set (_Flat_set_impl::erase_if): Replace
with ...
(_Flat_set_impl::_M_erase_if): ... this member function.
(flat_set): Export _Flat_set_impl::_M_erase_if.
(erase_if(flat_set)): Define.
(flat_multiset): Export _Flat_set_impl::_M_erase_if.
(erase_if(flat_multiset)): Define.
* testsuite/23_containers/flat_map/1.cc (test07): New test.
* testsuite/23_containers/flat_multimap/1.cc (test07): New test.
* testsuite/23_containers/flat_multiset/1.cc (test09): New test.
* testsuite/23_containers/flat_set/1.cc (test09): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/flat_map  | 28 ++
 libstdc++-v3/include/std/flat_set  | 28 +-
 libstdc++-v3/testsuite/23_containers/flat_map/1.cc | 11 +
 .../testsuite/23_containers/flat_multimap/1.cc | 11 +
 .../testsuite/23_containers/flat_multiset/1.cc | 11 +
 libstdc++-v3/testsuite/23_containers/flat_set/1.cc | 11 +
 6 files changed, 89 insertions(+), 11 deletions(-)

diff --git a/libstdc++-v3/include/std/flat_map 
b/libstdc++-v3/include/std/flat_map
index 405caa8a81bf..6593988d213c 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -890,14 +890,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   { return __x.swap(__y); }
 
   template
-   friend size_type
-   erase_if(_Derived& __c, _Predicate __pred)
+   size_type
+   _M_erase_if(_Predicate __pred)
{
- auto __guard = __c._M_make_clear_guard();
- auto __zv = views::zip(__c._M_cont.keys, __c._M_cont.values);
+ auto __guard = _M_make_clear_guard();
+ auto __zv = views::zip(_M_cont.keys, _M_cont.values);
  auto __sr = ranges::remove_if(__zv, __pred);
  auto __erased = __sr.size();
- __c.erase(__c.end() - __erased, __c.end());
+ erase(end() - __erased, end());
  __guard._M_disable();
  return __erased;
}
@@ -1329,6 +1329,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using _Impl::lower_bound;
   using _Impl::upper_bound;
   using _Impl::equal_range;
+
+  using _Impl::_M_erase_if;
 };
 
   template>
 { };
 
+  template
+typename flat_map<_Key, _Tp, _Compare, _KeyContainer, 
_MappedContainer>::size_type
+erase_if(flat_map<_Key, _Tp, _Compare, _KeyContainer, _MappedContainer>& 
__c,
+_Predicate __pred)
+{ return __c._M_erase_if(std::move(__pred)); }
+
   /* Class template flat_multimap - container adaptor
*
* @ingroup
@@ -1487,6 +1496,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using _Impl::lower_bound;
   using _Impl::upper_bound;
   using _Impl::equal_range;
+
+  using _Impl::_M_erase_if;
 };
 
   template>
 { };
 
+  template
+typename flat_multimap<_Key, _Tp, _Compare, _KeyContainer, 
_MappedContainer>::size_type
+erase_if(flat_multimap<_Key, _Tp, _Compare, _KeyContainer, 
_MappedContainer>& __c,
+_Predicate __pred)
+{ return __c._M_erase_if(std::move(__pred)); }
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 #endif // __cpp_lib_flat_map
diff --git a/libstdc++-v3/include/std/flat_set 
b/libstdc++-v3/include/std/flat_set
index 3e15d1af4162..c48340d79809 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -745,15 +745,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   { return __x.swap(__y); }
 
   template
-   friend size_type
-   erase_if(_Derived& __c, _Predicate __pred)
+   size_type
+   _M_erase_if(_Predicate __pred)
{
- auto __guard = __c._M_make_clear_guard();
- auto __first = __c._M_cont.begin();
- auto __last = __c._M_cont.end();
+ auto __guard = _M_make_clear_guard();
+ auto __first = _M_cont.begin();
+ auto __last = _M_cont.end();
  __first = std::remove_if(__first, __last, __pred);
  au

[gcc r15-7757] libstdc++: Fix constraint recursion in basic_const_iterator relops [PR112490]

2025-02-28 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:4342c50ca84ae5448c0128c52120f4fe9005f203

commit r15-7757-g4342c50ca84ae5448c0128c52120f4fe9005f203
Author: Patrick Palka 
Date:   Fri Feb 28 09:39:57 2025 -0500

libstdc++: Fix constraint recursion in basic_const_iterator relops 
[PR112490]

Here for

  using RCI = reverse_iterator::iterator>>
  static_assert(std::totally_ordered);

we effectively need to check the requirement

  requires (RCI x) { x RELOP x; }  for each RELOP in {<, >, <=, >=}

which we expect to be straightforwardly satisfied by reverse_iterator's
namespace-scope relops.  But due to ADL we find ourselves also
considering the basic_const_iterator relop friends, which before CWG
2369 would be quickly discarded since RCI clearly isn't convertible to
basic_const_iterator.  After CWG 2369 though we must first check these
relops' constraints (with _It = vector::iterator and _It2 = RCI),
which entails checking totally_ordered recursively.

This patch fixes this by turning the problematic non-dependent function
parameters of type basic_const_iterator<_It> into dependent ones of
type basic_const_iterator<_It3> where _It3 is constrained to match _It.
Thus the basic_const_iterator relop friends now get quickly discarded
during deduction and before the constraint check if the second operand
isn't a specialization of basic_const_iterator (or derived from one)
like before CWG 2369.

PR libstdc++/112490

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (basic_const_iterator::operator<):
Replace non-dependent basic_const_iterator function parameter with
a dependent one of type basic_const_iterator<_It3> where _It3
matches _It.
(basic_const_iterator::operator>): Likewise.
(basic_const_iterator::operator<=): Likewise.
(basic_const_iterator::operator>=): Likewise.
* testsuite/24_iterators/const_iterator/112490.cc: New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/stl_iterator.h | 16 
 .../testsuite/24_iterators/const_iterator/112490.cc  | 12 
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 3e025342fb52..33732b1a4287 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2881,30 +2881,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& three_way_comparable_with<_It, _It2>
   { return _M_current <=> __y; }
 
-template<__detail::__not_a_const_iterator _It2>
+template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
   friend constexpr bool
-  operator<(const _It2& __x, const basic_const_iterator& __y)
+  operator<(const _It2& __x, const basic_const_iterator<_It3>& __y)
   noexcept(noexcept(__x < __y._M_current))
   requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
   { return __x < __y._M_current; }
 
-template<__detail::__not_a_const_iterator _It2>
+template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
   friend constexpr bool
-  operator>(const _It2& __x, const basic_const_iterator& __y)
+  operator>(const _It2& __x, const basic_const_iterator<_It3>& __y)
   noexcept(noexcept(__x > __y._M_current))
   requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
   { return __x > __y._M_current; }
 
-template<__detail::__not_a_const_iterator _It2>
+template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
   friend constexpr bool
-  operator<=(const _It2& __x, const basic_const_iterator& __y)
+  operator<=(const _It2& __x, const basic_const_iterator<_It3>& __y)
   noexcept(noexcept(__x <= __y._M_current))
   requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
   { return __x <= __y._M_current; }
 
-template<__detail::__not_a_const_iterator _It2>
+template<__detail::__not_a_const_iterator _It2, same_as<_It> _It3>
   friend constexpr bool
-  operator>=(const _It2& __x, const basic_const_iterator& __y)
+  operator>=(const _It2& __x, const basic_const_iterator<_It3>& __y)
   noexcept(noexcept(__x >= __y._M_current))
   requires random_access_iterator<_It> && totally_ordered_with<_It, _It2>
   { return __x >= __y._M_current; }
diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc 
b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
new file mode 100644
index ..9bb154847cff
--- /dev/null
+++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++23 } }
+
+// PR libstdc++/112490 - infinite meta error in
+// reverse_iterator::iterator>>
+
+#include 
+#include 
+
+usin

[gcc r15-7840] libstdc++: Implement P3138R5 views::cache_latest

2025-03-05 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:410a4c126407c0ce048ad848d09cf4d39f578756

commit r15-7840-g410a4c126407c0ce048ad848d09cf4d39f578756
Author: Patrick Palka 
Date:   Wed Mar 5 16:46:15 2025 -0500

libstdc++: Implement P3138R5 views::cache_latest

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_cache_latest): Define.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__non_propagating_cache::_M_reset):
Export from base class _Optional_base.
(cache_latest_view): Define for C++26.
(cache_latest_view::_Iterator): Likewise.
(cache_latest_view::_Sentinel): Likewise.
(views::__detail::__can_cache_latest): Likewise.
(views::_CacheLatest, views::cache_latest): Likewise.
* testsuite/std/ranges/adaptors/cache_latest/1.cc: New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/version.def  |   8 +
 libstdc++-v3/include/bits/version.h|  10 ++
 libstdc++-v3/include/std/ranges| 189 +
 .../std/ranges/adaptors/cache_latest/1.cc  |  72 
 4 files changed, 279 insertions(+)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 0cdc2e82fc55..eb2c6d8a3ee7 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1846,6 +1846,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = ranges_cache_latest;
+  values = {
+v = 202411;
+cxxmin = 26;
+  };
+};
+
 ftms = {
   name = ranges_concat;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index ec52cba517fa..05dadd6fd19c 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2045,6 +2045,16 @@
 #endif /* !defined(__cpp_lib_is_virtual_base_of) && 
defined(__glibcxx_want_is_virtual_base_of) */
 #undef __glibcxx_want_is_virtual_base_of
 
+#if !defined(__cpp_lib_ranges_cache_latest)
+# if (__cplusplus >  202302L)
+#  define __glibcxx_ranges_cache_latest 202411L
+#  if defined(__glibcxx_want_all) || 
defined(__glibcxx_want_ranges_cache_latest)
+#   define __cpp_lib_ranges_cache_latest 202411L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_cache_latest) && 
defined(__glibcxx_want_ranges_cache_latest) */
+#undef __glibcxx_want_ranges_cache_latest
+
 #if !defined(__cpp_lib_ranges_concat)
 # if (__cplusplus >  202302L) && (__cpp_pack_indexing)
 #  define __glibcxx_ranges_concat 202403L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index def7527431cd..6790fcf7af19 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -57,6 +57,7 @@
 #define __glibcxx_want_ranges
 #define __glibcxx_want_ranges_as_const
 #define __glibcxx_want_ranges_as_rvalue
+#define __glibcxx_want_ranges_cache_latest
 #define __glibcxx_want_ranges_cartesian_product
 #define __glibcxx_want_ranges_concat
 #define __glibcxx_want_ranges_chunk
@@ -1534,6 +1535,8 @@ namespace views::__adaptor
this->_M_payload._M_apply(_Optional_func{__f}, __i);
return this->_M_get();
  }
+
+   using _Optional_base<_Tp>::_M_reset;
   };
 
 template
@@ -10201,6 +10204,192 @@ namespace ranges
 } // namespace ranges
 #endif // __cpp_lib_ranges_concat
 
+#if __cpp_lib_ranges_cache_latest // C++ >= 26
+namespace ranges
+{
+  template
+requires view<_Vp>
+  class cache_latest_view : public view_interface>
+  {
+_Vp _M_base = _Vp();
+
+using __cache_t = __conditional_t>,
+ add_pointer_t>,
+ range_reference_t<_Vp>>;
+__detail::__non_propagating_cache<__cache_t> _M_cache;
+
+class _Iterator;
+class _Sentinel;
+
+  public:
+cache_latest_view() requires default_initializable<_Vp> = default;
+
+constexpr explicit
+cache_latest_view(_Vp __base)
+: _M_base(std::move(__base))
+{ }
+
+constexpr _Vp
+base() const & requires copy_constructible<_Vp>
+{ return _M_base; }
+
+constexpr _Vp
+base() &&
+{ return std::move(_M_base); }
+
+constexpr auto
+begin()
+{ return _Iterator(*this); }
+
+constexpr auto
+end()
+{ return _Sentinel(*this); }
+
+constexpr auto
+size() requires sized_range<_Vp>
+{ return ranges::size(_M_base); }
+
+constexpr auto
+size() const requires sized_range
+{ return ranges::size(_M_base); }
+  };
+
+  template
+cache_latest_view(_Range&&) -> cache_latest_view>;
+
+  template
+requires view<_Vp>
+  class cache_latest_view<_Vp>::_Iterator
+  {
+cache_latest_view* _M_parent;
+iterator_t<_Vp> _M_current;
+
+constexpr explicit
+_Iterator(cache_latest_view& __parent)
+: _M_parent(std::__addressof(__parent)),
+  _M_current(ranges::begin(__parent._M_base))
+{ }
+
+friend clas

[gcc r15-7632] libstdc++: Sync concat_view with final P2542 revision [PR115209]

2025-02-19 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:8543dc52d84662e3fc0b8b6ac5e98ce13ebe9ad9

commit r15-7632-g8543dc52d84662e3fc0b8b6ac5e98ce13ebe9ad9
Author: Patrick Palka 
Date:   Wed Feb 19 22:59:49 2025 -0500

libstdc++: Sync concat_view with final P2542 revision [PR115209]

Our concat_view implementation is accidentally based off of an older
revision of the paper, P2542R7 instead of R8.  As far as I can tell the
only semantic change in the final revision is the relaxed constraints on
the iterator's iter/sent operator- overloads, which this patch updates.

This patch also simplifies the concat_view::end wording via C++26 pack
indexing as per the final revision.  In turn we make the availability of
this library feature conditional on __cpp_pack_indexing.  (Note pack
indexing is implemented in GCC 15 and Clang 19).

PR libstdc++/115209

libstdc++-v3/ChangeLog:

* include/bits/version.def (ranges_concat): Depend on
__cpp_pack_indexing.
* include/bits/version.h: Regenerate.
* include/std/ranges (__detail::__last_is_common): Remove.
(__detail::__all_but_first_sized): New.
(concat_view::end): Use C++26 pack indexing instead of
__last_is_common as per R8 of P2542.
(concat_view::iterator::operator-): Update constraints on
iter/sent overloads as per R8 of P2542.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/version.def |  1 +
 libstdc++-v3/include/bits/version.h   |  2 +-
 libstdc++-v3/include/std/ranges   | 38 +++
 3 files changed, 18 insertions(+), 23 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 002e560dc0d2..e75befe7f4b1 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1842,6 +1842,7 @@ ftms = {
   values = {
 v = 202403;
 cxxmin = 26;
+extra_cond = "__cpp_pack_indexing";
   };
 };
 
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 70de189b1e0b..cd713ee54ea3 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2036,7 +2036,7 @@
 #undef __glibcxx_want_is_virtual_base_of
 
 #if !defined(__cpp_lib_ranges_concat)
-# if (__cplusplus >  202302L)
+# if (__cplusplus >  202302L) && (__cpp_pack_indexing)
 #  define __glibcxx_ranges_concat 202403L
 #  if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_concat)
 #   define __cpp_lib_ranges_concat 202403L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 5c795a90fbc2..22e0c9cae447 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9683,12 +9683,8 @@ namespace ranges
&& __all_but_last_common<_Const, _Rs...>::value;
 
 template
-  struct __last_is_common
-  { static inline constexpr bool value = __last_is_common<_Rs...>::value; 
};
-
-template
-  struct __last_is_common<_Range>
-  { static inline constexpr bool value = common_range<_Range>; };
+  struct __all_but_first_sized
+  { static inline constexpr bool value = (sized_range<_Rs> && ...); };
   } // namespace __detail
 
   template
@@ -9726,13 +9722,11 @@ namespace ranges
 constexpr auto
 end() requires (!(__detail::__simple_view<_Vs> && ...))
 {
+  constexpr auto __n = sizeof...(_Vs);
   if constexpr ((semiregular> && ...)
-   && __detail::__last_is_common<_Vs...>::value)
-   {
- constexpr auto __n = sizeof...(_Vs);
- return iterator(this, in_place_index<__n - 1>,
-ranges::end(std::get<__n - 1>(_M_views)));
-   }
+   && common_range<_Vs...[__n - 1]>)
+   return iterator(this, in_place_index<__n - 1>,
+  ranges::end(std::get<__n - 1>(_M_views)));
   else
return default_sentinel;
 }
@@ -9740,13 +9734,11 @@ namespace ranges
 constexpr auto
 end() const requires (range && ...) && 
__detail::__concatable
 {
+  constexpr auto __n = sizeof...(_Vs);
   if constexpr ((semiregular> && ...)
-   && __detail::__last_is_common::value)
-   {
- constexpr auto __n = sizeof...(_Vs);
- return iterator(this, in_place_index<__n - 1>,
-   ranges::end(std::get<__n - 1>(_M_views)));
-   }
+   && common_range)
+   return iterator(this, in_place_index<__n - 1>,
+ ranges::end(std::get<__n - 1>(_M_views)));
   else
return default_sentinel;
 }
@@ -10128,8 +10120,9 @@ namespace ranges
 
 friend constexpr difference_type
 operator-(const iterator& __x, default_sentinel_t)
-  requires __detail::__concat_is_random_access<_Const, _Vs...>
-   && __detail::__last_is_common<__maybe_const_t<

[gcc r15-7698] libstdc++: Implement LWG 4027 change to possibly-const-range [PR118083]

2025-02-25 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:1b9e4fe2ff5f4711406cdcf0e6e183b247d9f42b

commit r15-7698-g1b9e4fe2ff5f4711406cdcf0e6e183b247d9f42b
Author: Patrick Palka 
Date:   Tue Feb 25 13:35:04 2025 -0500

libstdc++: Implement LWG 4027 change to possibly-const-range [PR118083]

LWG 4027 effectively makes the const range access CPOs ranges::cfoo behave
more consistently across C++23 and C++20 (pre-P2278R4) and also more
consistently with the std::cfoo range accessors, as the below testcase
adjustments demonstrate (which mostly consist of reverting workarounds
added by r14-3771-gf12e26f3496275 and r13-7186-g0d94c6df183375).

In passing fix PR118083 which reports that the input_range constraint on
possibly-const-range is missing in our implementation.  A consequence of
this is that the const range access CPOs now consistently reject a non-range
argument, and so in some our of tests we need to introduce otherwise
unused begin/end members.

PR libstdc++/118083

libstdc++-v3/ChangeLog:

* include/bits/ranges_base.h
(ranges::__access::__possibly_const_range): Adjust logic as per
LWG 4027.  Add missing input_range constraint.
* testsuite/std/ranges/access/cbegin.cc (test05): Verify LWG
4027 testcases.
* testsuite/std/ranges/access/cdata.cc: Adjust, simplify and
consolidate some tests after the above.
* testsuite/std/ranges/access/cend.cc: Likewise.
* testsuite/std/ranges/access/crbegin.cc: Likewise.
* testsuite/std/ranges/access/crend.cc: Likewise.
* testsuite/std/ranges/adaptors/join.cc: Likewise.
* testsuite/std/ranges/adaptors/take_while.cc: Likewise.
* testsuite/std/ranges/adaptors/transform.cc: Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_base.h|  4 +-
 libstdc++-v3/testsuite/std/ranges/access/cbegin.cc | 17 +
 libstdc++-v3/testsuite/std/ranges/access/cdata.cc  | 21 ++-
 libstdc++-v3/testsuite/std/ranges/access/cend.cc   | 30 ++-
 .../testsuite/std/ranges/access/crbegin.cc | 43 +-
 libstdc++-v3/testsuite/std/ranges/access/crend.cc  | 20 ++
 libstdc++-v3/testsuite/std/ranges/adaptors/join.cc |  8 ++--
 .../testsuite/std/ranges/adaptors/take_while.cc|  2 -
 .../testsuite/std/ranges/adaptors/transform.cc |  4 --
 9 files changed, 59 insertions(+), 90 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index 4dcfbf66d51f..28fe64a9e9da 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -642,11 +642,11 @@ namespace ranges
   namespace __access
   {
 #if __glibcxx_ranges_as_const // >= C++23
-template
+template
   constexpr auto&
   __possibly_const_range(_Range& __r) noexcept
   {
-   if constexpr (constant_range && !constant_range<_Range>)
+   if constexpr (input_range)
  return const_cast(__r);
else
  return __r;
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc 
b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
index 5423e7824282..c85303d3e357 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cbegin.cc
@@ -116,10 +116,27 @@ test04()
   VERIFY(std::ranges::cbegin(std::move(c)) == std::ranges::begin(c));
 }
 
+void
+test05()
+{
+  // LWG 4027 - possibly-const-range should prefer returning const R&
+  auto r = std::views::single(0)
+| std::views::transform([](int) { return 0; });
+  using C1 = decltype(std::ranges::cbegin(r));
+  using C1 = decltype(std::cbegin(r));
+
+  [] (auto x) {
+auto r = std::views::single(x) | std::views::lazy_split(0);
+static_assert(!requires { (*std::ranges::cbegin(r)).front() = 42; });
+static_assert(!requires { (*std::cbegin(r)).front() = 42; });
+  }(0);
+}
+
 int
 main()
 {
   test01();
   test03();
   test04();
+  test05();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc 
b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
index 62c347be43d6..f474ab7ec99c 100644
--- a/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
+++ b/libstdc++-v3/testsuite/std/ranges/access/cdata.cc
@@ -34,20 +34,21 @@ test01()
   {
 int i = 0;
 int j = 0;
+
+#if __cpp_lib_ranges_as_const
+// These overloads mean that range and range are satisfied.
+const int* begin() const { throw; }
+const int* end() const { throw; }
+#endif
+
 int* data() { return &j; }
 const R* data() const noexcept { return nullptr; }
   };
   static_assert( has_cdata );
   static_assert( has_cdata );
   R r;
-#if ! __cpp_lib_ranges_as_const
   VERIFY( std::ranges::cdata(r) == (R*)nullptr );
   static_assert( noexcept(std::ranges::cdata(r)) );
-#else
-  // constant_range is not satisfied, so cdata(r) 

[gcc r15-9211] libstdc++: Avoid redundant value_type object in flat_set::emplace [PR119620]

2025-04-04 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:2a36d22ab52d6ffce9a1fcaf7aca83336679e111

commit r15-9211-g2a36d22ab52d6ffce9a1fcaf7aca83336679e111
Author: Patrick Palka 
Date:   Fri Apr 4 15:05:09 2025 -0400

libstdc++: Avoid redundant value_type object in flat_set::emplace [PR119620]

flat_set::emplace (and flat_multiset's) currently unconditionally
constructs an object outside of the container, but if we're passed
a value_type object we can and should avoid that.

PR libstdc++/119620

libstdc++-v3/ChangeLog:

* include/std/flat_set (_Flat_set_impl::_M_try_emplace): Split
out into two overloads, one taking at least one argument and one
taking zero arguments.  Turn __k into an auto&& reference bound
to __arg if it's already a value_type and otherwise bound to a
lifetime-extended value_type temporary.
* testsuite/23_containers/flat_multiset/1.cc (test08): New test.
* testsuite/23_containers/flat_set/1.cc (test08): New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/flat_set  | 20 
 .../testsuite/23_containers/flat_multiset/1.cc | 22 ++
 libstdc++-v3/testsuite/23_containers/flat_set/1.cc | 20 
 3 files changed, 58 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/flat_set 
b/libstdc++-v3/include/std/flat_set
index a7b0b8aef151..3e15d1af4162 100644
--- a/libstdc++-v3/include/std/flat_set
+++ b/libstdc++-v3/include/std/flat_set
@@ -350,12 +350,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   { return _M_cont.max_size(); }
 
   // modifiers
-  template
+  template
pair
-   _M_try_emplace(optional __hint, _Args&&... __args)
+   _M_try_emplace(optional __hint, _Arg&& __arg, 
_Args&&... __args)
{
  // TODO: Simplify and audit the hint handling.
- value_type __k(std::forward<_Args>(__args)...);
+ auto&& __k = [&] -> decltype(auto) {
+   if constexpr (sizeof...(_Args) == 0
+ && same_as, value_type>)
+ return std::forward<_Arg>(__arg);
+   else
+ return value_type(std::forward<_Arg>(__arg),
+   std::forward<_Args>(__args)...);
+ }();
  typename container_type::iterator __it;
  int __r = -1, __s = -1;
  if (__hint.has_value()
@@ -397,11 +404,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  return {__it, false};
 
  auto __guard = _M_make_clear_guard();
- __it = _M_cont.insert(__it, std::move(__k));
+ __it = _M_cont.insert(__it, std::forward(__k));
  __guard._M_disable();
  return {__it, true};
}
 
+  template
+   pair
+   _M_try_emplace(optional __hint)
+   { return _M_try_emplace(__hint, value_type()); }
+
   template
requires is_constructible_v
__emplace_result_t
diff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
index dc3cecd9720c..7d9a33c6b000 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc
@@ -214,6 +214,27 @@ void test07()
 #endif
 }
 
+void
+test08()
+{
+  // PR libstdc++/119620 -- flat_set::emplace always constructs element on the 
stack
+  static int copy_counter;
+  struct A {
+A() { }
+A(const A&) { ++copy_counter; }
+A& operator=(const A&) { ++copy_counter; return *this; }
+auto operator<=>(const A&) const = default;
+  };
+  std::vector v;
+  v.reserve(2);
+  std::flat_multiset s(std::move(v));
+  A a;
+  s.emplace(a);
+  VERIFY( copy_counter == 1 );
+  s.emplace(a);
+  VERIFY( copy_counter == 2 );
+}
+
 int
 main()
 {
@@ -225,4 +246,5 @@ main()
   test05();
   test06();
   test07();
+  test08();
 }
diff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc 
b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
index 90f5855859f7..ed24fab785b5 100644
--- a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc
@@ -229,6 +229,25 @@ void test07()
 #endif
 }
 
+void
+test08()
+{
+  // PR libstdc++/119620 -- flat_set::emplace always constructs element on the 
stack
+  static int copy_counter;
+  struct A {
+A() { }
+A(const A&) { ++copy_counter; }
+A& operator=(const A&) { ++copy_counter; return *this; }
+auto operator<=>(const A&) const = default;
+  };
+  std::flat_set s;
+  A a;
+  s.emplace(a);
+  VERIFY( copy_counter == 1 );
+  s.emplace(a);
+  VERIFY( copy_counter == 1 );
+}
+
 int
 main()
 {
@@ -240,4 +259,5 @@ main()
   test05();
   test06();
   test07();
+  test08();
 }


[gcc r15-9660] libstdc++: Fix constraint recursion in std::expected's operator== [PR119714]

2025-05-12 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:0b76b58a5875d519f95a5af661fb64e42a42ed8e

commit r15-9660-g0b76b58a5875d519f95a5af661fb64e42a42ed8e
Author: Patrick Palka 
Date:   Mon May 12 09:15:34 2025 -0400

libstdc++: Fix constraint recursion in std::expected's operator== [PR119714]

This std::expected friend operator== is prone to constraint recursion
after CWG 2369 for the same reason as basic_const_iterator's comparison
operators were before the r15-7757-g4342c50ca84ae5 workaround.  This
patch works around the constraint recursion here in a similar manner,
by making the function parameter of type std::expected dependent in a
trivial way.

PR libstdc++/119714
PR libstdc++/112490

libstdc++-v3/ChangeLog:

* include/std/expected (expected::operator==): Replace
non-dependent std::expected function parameter with a dependent
one of type expected<_Vp, _Er> where _Vp matches _Tp.
* testsuite/20_util/expected/119714.cc: New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 
(cherry picked from commit 91bc8169edd9038d78f38bd813287d72e6345c26)

Diff:
---
 libstdc++-v3/include/std/expected | 4 ++--
 libstdc++-v3/testsuite/20_util/expected/119714.cc | 9 +
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/expected 
b/libstdc++-v3/include/std/expected
index 5dc1dfbe5b8a..60f1565f15b9 100644
--- a/libstdc++-v3/include/std/expected
+++ b/libstdc++-v3/include/std/expected
@@ -1169,13 +1169,13 @@ namespace __expected
return !__y.has_value() && bool(__x.error() == __y.error());
}
 
-  template
+  template _Vp>
requires (!__expected::__is_expected<_Up>)
  && requires (const _Tp& __t, const _Up& __u) {
{ __t == __u } -> convertible_to;
  }
friend constexpr bool
-   operator==(const expected& __x, const _Up& __v)
+   operator==(const expected<_Vp, _Er>& __x, const _Up& __v)
noexcept(noexcept(bool(*__x == __v)))
{ return __x.has_value() && bool(*__x == __v); }
 
diff --git a/libstdc++-v3/testsuite/20_util/expected/119714.cc 
b/libstdc++-v3/testsuite/20_util/expected/119714.cc
new file mode 100644
index ..a8dc6e891e1d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/expected/119714.cc
@@ -0,0 +1,9 @@
+// { dg-do compile { target c++23 } }
+
+// PR libstdc++/119714 - constraint recursion with std::expected::operator==
+
+#include 
+#include 
+
+using I = std::vector>::iterator;
+static_assert(std::totally_ordered);


[gcc r16-2271] libstdc++: Add missing initializers for __maybe_present_t members [PR119962]

2025-07-15 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:0828600f586e75a2056a4fc7eb0a340c363d6c66

commit r16-2271-g0828600f586e75a2056a4fc7eb0a340c363d6c66
Author: Patrick Palka 
Date:   Tue Jul 15 15:17:23 2025 -0400

libstdc++: Add missing initializers for __maybe_present_t members [PR119962]

Data members of type __maybe_present_t where the conditionally present
type might be an aggregate or fundamental type need to be explicitly
value-initialized (rather than implicitly default-initialized), so that
default-initialization of the containing class always results in an
completely initialized object.

PR libstdc++/119962

libstdc++-v3/ChangeLog:

* include/std/ranges (join_view::_Iterator::_M_outer): Initialize.
(lazy_split_view::_OuterIter::_M_current): Initialize.
(join_with_view::_Iterator::_M_outer_it): Initialize.
* testsuite/std/ranges/adaptors/join.cc (test15): New test.
* testsuite/std/ranges/adaptors/join_with/1.cc (test05): New test.
* testsuite/std/ranges/adaptors/lazy_split.cc (test13): New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges   | 9 ++---
 libstdc++-v3/testsuite/std/ranges/adaptors/join.cc| 8 
 libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc | 8 
 libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc  | 8 
 4 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 3a6710bd0ae1..efe62969d657 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -3022,7 +3022,8 @@ namespace views::__adaptor
  { _M_satisfy(); }
 
  [[no_unique_address]]
-   __detail::__maybe_present_t, _Outer_iter> 
_M_outer;
+   __detail::__maybe_present_t, _Outer_iter> 
_M_outer
+ = decltype(_M_outer)();
  optional<_Inner_iter> _M_inner;
  _Parent* _M_parent = nullptr;
 
@@ -3376,7 +3377,8 @@ namespace views::__adaptor
 
  [[no_unique_address]]
__detail::__maybe_present_t,
-   iterator_t<_Base>> _M_current;
+   iterator_t<_Base>> _M_current
+ = decltype(_M_current)();
  bool _M_trailing_empty = false;
 
public:
@@ -7400,7 +7402,8 @@ namespace views::__adaptor
 
 _Parent* _M_parent = nullptr;
 [[no_unique_address]]
-  __detail::__maybe_present_t, _OuterIter> 
_M_outer_it;
+  __detail::__maybe_present_t, _OuterIter> _M_outer_it
+   = decltype(_M_outer_it)();
 variant<_PatternIter, _InnerIter> _M_inner_it;
 
 constexpr _OuterIter&
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
index 2861115c22a0..a9395b489919 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
@@ -233,6 +233,13 @@ test14()
   VERIFY( ranges::equal(v | views::join, (int[]){1, 2, 3}) );
 }
 
+void
+test15()
+{
+  // PR libstdc++/119962 - __maybe_present_t misses initialization
+  constexpr decltype(views::join(views::single(views::single(0))).begin()) it;
+}
+
 int
 main()
 {
@@ -250,4 +257,5 @@ main()
   test12();
   test13();
   test14();
+  test15();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
index 8ab30a5277da..4d55c9d3be78 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join_with/1.cc
@@ -94,6 +94,13 @@ test04()
   return true;
 }
 
+void
+test05()
+{
+  // PR libstdc++/119962 - __maybe_present_t misses initialization
+  constexpr decltype(views::join_with(views::single(views::single(0)), 
0).begin()) it;
+}
+
 int
 main()
 {
@@ -105,4 +112,5 @@ main()
 #else
   VERIFY(test04());
 #endif
+  test05();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
index 81fc60b362a8..321ae271bf2b 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc
@@ -232,6 +232,13 @@ test12()
   return true;
 }
 
+void
+test13()
+{
+  // PR libstdc++/119962 - __maybe_present_t misses initialization
+  constexpr decltype(views::lazy_split(views::single(0), 0).begin()) it;
+}
+
 int
 main()
 {
@@ -247,4 +254,5 @@ main()
   test10();
   test11();
   static_assert(test12());
+  test13();
 }


[gcc r15-9917] libstdc++: Update LWG 4166 changes to concat_view::end() [PR120934]

2025-07-03 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:612690936f5ddd122b60cf843cb4f40ae7ede436

commit r15-9917-g612690936f5ddd122b60cf843cb4f40ae7ede436
Author: Patrick Palka 
Date:   Thu Jul 3 10:55:17 2025 -0400

libstdc++: Update LWG 4166 changes to concat_view::end() [PR120934]

In r15-4555-gf191c830154565 we proactively implemented the initial
proposed resolution for LWG 4166 which later turned out to be
insufficient, since we must also require equality_comparable of the
underlying iterators before concat_view could be a common range.

This patch implements the updated P/R, requiring all underlying
iterators to be forward (which implies equality_comparable) before
making concat_view common, which fixes the testcase from this PR.

PR libstdc++/120934

libstdc++-v3/ChangeLog:

* include/std/ranges (concat_view::end): Refine condition
for returning an iterator instead of default_sentinel as
per the updated P/R for LWG 4166.
* testsuite/std/ranges/concat/1.cc (test05): New test.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit c5a17e92ebf0c6f3887fb5698a1114a3fdf50576)

Diff:
---
 libstdc++-v3/include/std/ranges   |  4 ++--
 libstdc++-v3/testsuite/std/ranges/concat/1.cc | 13 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 210ac8274fc1..8756065d 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9735,7 +9735,7 @@ namespace ranges
 end() requires (!(__detail::__simple_view<_Vs> && ...))
 {
   constexpr auto __n = sizeof...(_Vs);
-  if constexpr ((semiregular> && ...)
+  if constexpr (__detail::__all_forward
&& common_range<_Vs...[__n - 1]>)
return _Iterator(this, in_place_index<__n - 1>,
ranges::end(std::get<__n - 1>(_M_views)));
@@ -9747,7 +9747,7 @@ namespace ranges
 end() const requires (range && ...) && 
__detail::__concatable
 {
   constexpr auto __n = sizeof...(_Vs);
-  if constexpr ((semiregular> && ...)
+  if constexpr (__detail::__all_forward
&& common_range)
return _Iterator(this, in_place_index<__n - 1>,
   ranges::end(std::get<__n - 1>(_M_views)));
diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc 
b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
index 16721912a37d..f78ed08a610b 100644
--- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
@@ -99,6 +99,18 @@ test04()
   using type = decltype(v);
 }
 
+void
+test05()
+{
+  // PR libstdc++/120934 - views::concat is ill-formed depending on argument 
order
+  auto v1 = views::single(1);
+  std::vector vec = {2, 3};
+  auto v2 = views::join(views::transform(vec, views::single));
+
+  static_assert( ranges::range );
+  static_assert( ranges::range );
+}
+
 int
 main()
 {
@@ -107,4 +119,5 @@ main()
   test02();
   test03();
   test04();
+  test05();
 }


[gcc r16-1986] libstdc++: Update LWG 4166 changes to concat_view::end() [PR120934]

2025-07-03 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:c5a17e92ebf0c6f3887fb5698a1114a3fdf50576

commit r16-1986-gc5a17e92ebf0c6f3887fb5698a1114a3fdf50576
Author: Patrick Palka 
Date:   Thu Jul 3 10:55:17 2025 -0400

libstdc++: Update LWG 4166 changes to concat_view::end() [PR120934]

In r15-4555-gf191c830154565 we proactively implemented the initial
proposed resolution for LWG 4166 which later turned out to be
insufficient, since we must also require equality_comparable of the
underlying iterators before concat_view could be a common range.

This patch implements the updated P/R, requiring all underlying
iterators to be forward (which implies equality_comparable) before
making concat_view common, which fixes the testcase from this PR.

PR libstdc++/120934

libstdc++-v3/ChangeLog:

* include/std/ranges (concat_view::end): Refine condition
for returning an iterator instead of default_sentinel as
per the updated P/R for LWG 4166.
* testsuite/std/ranges/concat/1.cc (test05): New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges   |  4 ++--
 libstdc++-v3/testsuite/std/ranges/concat/1.cc | 13 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index f764aa7512e3..3a6710bd0ae1 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -9735,7 +9735,7 @@ namespace ranges
 end() requires (!(__detail::__simple_view<_Vs> && ...))
 {
   constexpr auto __n = sizeof...(_Vs);
-  if constexpr ((semiregular> && ...)
+  if constexpr (__detail::__all_forward
&& common_range<_Vs...[__n - 1]>)
return _Iterator(this, in_place_index<__n - 1>,
ranges::end(std::get<__n - 1>(_M_views)));
@@ -9747,7 +9747,7 @@ namespace ranges
 end() const requires (range && ...) && 
__detail::__concatable
 {
   constexpr auto __n = sizeof...(_Vs);
-  if constexpr ((semiregular> && ...)
+  if constexpr (__detail::__all_forward
&& common_range)
return _Iterator(this, in_place_index<__n - 1>,
   ranges::end(std::get<__n - 1>(_M_views)));
diff --git a/libstdc++-v3/testsuite/std/ranges/concat/1.cc 
b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
index 16721912a37d..f78ed08a610b 100644
--- a/libstdc++-v3/testsuite/std/ranges/concat/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/concat/1.cc
@@ -99,6 +99,18 @@ test04()
   using type = decltype(v);
 }
 
+void
+test05()
+{
+  // PR libstdc++/120934 - views::concat is ill-formed depending on argument 
order
+  auto v1 = views::single(1);
+  std::vector vec = {2, 3};
+  auto v2 = views::join(views::transform(vec, views::single));
+
+  static_assert( ranges::range );
+  static_assert( ranges::range );
+}
+
 int
 main()
 {
@@ -107,4 +119,5 @@ main()
   test02();
   test03();
   test04();
+  test05();
 }


[gcc r16-1901] libstdc++: Use ranges::iter_move in ranges::remove_if [PR120789]

2025-07-01 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:17e9ae215f991f2f94fe480aee2404c508388b7c

commit r16-1901-g17e9ae215f991f2f94fe480aee2404c508388b7c
Author: Patrick Palka 
Date:   Tue Jul 1 13:43:12 2025 -0400

libstdc++: Use ranges::iter_move in ranges::remove_if [PR120789]

PR libstdc++/120789

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__remove_if_fn::operator()): Use
ranges::iter_move(iter) instead of std::move(*iter).
* testsuite/25_algorithms/remove_if/120789.cc: New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h|  2 +-
 .../testsuite/25_algorithms/remove_if/120789.cc| 36 ++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 7aea5c9fa70c..cf369c5d4dde 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1294,7 +1294,7 @@ namespace ranges
for (; __first != __last; ++__first)
  if (!std::__invoke(__pred, std::__invoke(__proj, *__first)))
{
- *__result = std::move(*__first);
+ *__result = ranges::iter_move(__first);
  ++__result;
}
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc 
b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc
new file mode 100644
index ..c1f4eeb9b4dd
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove_if/120789.cc
@@ -0,0 +1,36 @@
+// PR libstdc++/120789 - ranges::remove_if should use ranges::iter_move
+// { dg-do compile { target c++20 } }
+
+#include 
+
+struct A
+{
+  bool operator==(const A&) const;
+};
+
+struct B
+{
+  B(B&&) = delete;
+  B& operator=(const A&) const;
+
+  operator A() const;
+  bool operator==(const B&) const;
+};
+
+struct I
+{
+  using value_type = A;
+  using difference_type = int;
+  B operator*() const;
+  I& operator++();
+  I operator++(int);
+  bool operator==(const I&) const;
+  friend A iter_move(const I&);
+};
+
+void
+test01()
+{
+  std::ranges::subrange r;
+  auto [begin, end] = std::ranges::remove_if(r, [](auto&&) { return true; });
+}


[gcc r16-1900] libstdc++: Use ranges::iter_move in ranges::unique [PR120789]

2025-07-01 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:6f69a68998f601cdb86c65113eb1feddfa9da31a

commit r16-1900-g6f69a68998f601cdb86c65113eb1feddfa9da31a
Author: Patrick Palka 
Date:   Tue Jul 1 13:43:09 2025 -0400

libstdc++: Use ranges::iter_move in ranges::unique [PR120789]

PR libstdc++/120789

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__unique_fn::operator()): Use
ranges::iter_move(iter) instead of std::move(*iter).
* testsuite/25_algorithms/unique/120789.cc: New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h|  2 +-
 .../testsuite/25_algorithms/unique/120789.cc   | 36 ++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 2df730eabc8b..7aea5c9fa70c 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1454,7 +1454,7 @@ namespace ranges
  if (!std::__invoke(__comp,
 std::__invoke(__proj, *__dest),
 std::__invoke(__proj, *__first)))
-   *++__dest = std::move(*__first);
+   *++__dest = ranges::iter_move(__first);
return {++__dest, __first};
   }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc 
b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc
new file mode 100644
index ..24b107132473
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique/120789.cc
@@ -0,0 +1,36 @@
+// PR libstdc++/120789 - ranges::unique should use ranges::iter_move
+// { dg-do compile { target c++20 } }
+
+#include 
+
+struct A
+{
+  bool operator==(const A&) const;
+};
+
+struct B
+{
+  B(B&&) = delete;
+  B& operator=(const A&) const;
+
+  operator A() const;
+  bool operator==(const B&) const;
+};
+
+struct I
+{
+  using value_type = A;
+  using difference_type = int;
+  B operator*() const;
+  I& operator++();
+  I operator++(int);
+  bool operator==(const I&) const;
+  friend A iter_move(const I&);
+};
+
+void
+test01()
+{
+  std::ranges::subrange r;
+  auto [begin, end] = std::ranges::unique(r);
+}


[gcc r16-1743] libstdc++: Directly implement ranges::stable_sort [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:04c597c05494e38cc9c231581737c1d7d7579e51

commit r16-1743-g04c597c05494e38cc9c231581737c1d7d7579e51
Author: Patrick Palka 
Date:   Fri Jun 27 13:53:29 2025 -0400

libstdc++: Directly implement ranges::stable_sort [PR100795]

PR libstdc++/100795

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__detail::__move_merge): New,
based on the stl_algo.h implementation.
(__detail::__merge_sort_loop): Likewise.
(__detail::__chunk_insertion_sort): Likewise.
(__detail::__merge_sort_with_buffer): Likewise.
(__detail::__stable_sort_adaptive): Likewise.
(__detail::__stable_sort_adaptive_resize): Likewise.
(__detail::__inplace_stable_sort): Likewise.
(__stable_sort_fn::operator()): Reimplement in terms of the above.
* testsuite/25_algorithms/stable_sort/constrained.cc:

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 207 -
 .../25_algorithms/stable_sort/constrained.cc   |  30 +++
 2 files changed, 233 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index b0357600adbc..d0d3d92bd52c 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -2388,6 +2388,169 @@ namespace ranges
 
   inline constexpr __sort_fn sort{};
 
+  namespace __detail
+  {
+// This is a helper function for the __merge_sort_loop routines.
+template
+  _Out
+  __move_merge(_Iter __first1, _Iter __last1,
+  _Iter __first2, _Iter __last2,
+  _Out __result, _Comp __comp)
+  {
+   while (__first1 != __last1 && __first2 != __last2)
+ {
+   if (__comp(*__first2, *__first1))
+ {
+   *__result = ranges::iter_move(__first2);
+   ++__first2;
+ }
+   else
+ {
+   *__result = ranges::iter_move(__first1);
+   ++__first1;
+ }
+   ++__result;
+ }
+   return ranges::move(__first2, __last2,
+   ranges::move(__first1, __last1, __result).out).out;
+  }
+
+template
+  void
+  __merge_sort_loop(_Iter __first, _Iter __last, _Out __result,
+   _Distance __step_size, _Comp __comp)
+  {
+   const _Distance __two_step = 2 * __step_size;
+
+   while (__last - __first >= __two_step)
+ {
+   __result = __detail::__move_merge(__first, __first + __step_size,
+ __first + __step_size,
+ __first + __two_step,
+ __result, __comp);
+   __first += __two_step;
+ }
+   __step_size = ranges::min(_Distance(__last - __first), __step_size);
+
+   __detail::__move_merge(__first, __first + __step_size,
+  __first + __step_size, __last, __result, __comp);
+  }
+
+template
+  constexpr void
+  __chunk_insertion_sort(_Iter __first, _Iter __last,
+_Distance __chunk_size, _Compare __comp)
+  {
+   while (__last - __first >= __chunk_size)
+ {
+   __detail::__insertion_sort(__first, __first + __chunk_size, __comp);
+   __first += __chunk_size;
+ }
+   __detail::__insertion_sort(__first, __last, __comp);
+  }
+
+template
+  void
+  __merge_sort_with_buffer(_Iter __first, _Iter __last,
+  _Pointer __buffer, _Comp __comp)
+  {
+   using _Distance = iter_difference_t<_Iter>;
+
+   const _Distance __len = __last - __first;
+   const _Pointer __buffer_last = __buffer + ptrdiff_t(__len);
+
+   constexpr int __chunk_size = 7;
+   _Distance __step_size = __chunk_size;
+   __detail::__chunk_insertion_sort(__first, __last, __step_size, __comp);
+
+   while (__step_size < __len)
+ {
+   __detail::__merge_sort_loop(__first, __last, __buffer,
+   __step_size, __comp);
+   __step_size *= 2;
+   __detail::__merge_sort_loop(__buffer, __buffer_last, __first,
+   ptrdiff_t(__step_size), __comp);
+   __step_size *= 2;
+ }
+  }
+
+template
+  void
+  __merge_adaptive(_Iter __first, _Iter __middle, _Iter __last,
+  iter_difference_t<_Iter> __len1,
+  iter_difference_t<_Iter> __len2,
+  _Pointer __buffer, _Comp __comp); // defined near 
inplace_merge
+
+template
+  void
+  __merge_adaptive_resize(_Iter __first, _Iter __middle, _Iter __last,
+ _Distance __len1, _Distance __len2,
+  

[gcc r16-1742] libstdc++: Directly implement ranges::inplace_merge [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:9d3467a14bbd75469f114b047590ebbffa4a9c8b

commit r16-1742-g9d3467a14bbd75469f114b047590ebbffa4a9c8b
Author: Patrick Palka 
Date:   Fri Jun 27 13:53:26 2025 -0400

libstdc++: Directly implement ranges::inplace_merge [PR100795]

As with the previous patch, this patch reimplements ranges::inplace_merge
directly instead of incorrectly forwarding to std::inplace_merge.  In
addition to the compatibility changes listed in the previous patch we
also:

  - explicitly cast the difference type (which can be an integer class) to
ptrdiff_t when constructing a _Temporary_buffer

PR libstdc++/100795

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__detail::__move_merge_adaptive):
New, based on the stl_algo.h implementation.
(__detail::__move_merge_adaptive_backward): Likewise.
(__detail::__rotate_adaptive): Likewise.
(__detail::__merge_adaptive): Likewise.
(__detail::__merge_adaptive_resize): Likewise.
(__detail::__merge_without_buffer): Likewise.
(__inplace_merge_fn::operator()): Reimplement in terms of the
above.
* testsuite/25_algorithms/inplace_merge/constrained.cc (test03):
New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 257 -
 .../25_algorithms/inplace_merge/constrained.cc |  36 +++
 2 files changed, 289 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index de935dde4f70..b0357600adbc 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -3145,6 +3145,215 @@ namespace ranges
 
   inline constexpr __merge_fn merge{};
 
+  namespace __detail
+  {
+template
+  void
+  __move_merge_adaptive(_Iter1 __first1, _Iter1 __last1,
+   _Iter2 __first2, _Iter2 __last2,
+   _Out __result, _Comp __comp)
+  {
+   while (__first1 != __last1 && __first2 != __last2)
+ {
+   if (__comp(*__first2, *__first1))
+ {
+   *__result = ranges::iter_move(__first2);
+   ++__first2;
+ }
+   else
+ {
+   *__result = ranges::iter_move(__first1);
+   ++__first1;
+ }
+   ++__result;
+ }
+   if (__first1 != __last1)
+ ranges::move(__first1, __last1, __result);
+  }
+
+template
+  void
+  __move_merge_adaptive_backward(_Iter1 __first1, _Iter1 __last1,
+_Iter2 __first2, _Iter2 __last2,
+_Iter3 __result, _Comp __comp)
+  {
+   if (__first1 == __last1)
+ {
+   ranges::move_backward(__first2, __last2, __result);
+   return;
+ }
+   else if (__first2 == __last2)
+ return;
+
+   --__last1;
+   --__last2;
+   while (true)
+ {
+   if (__comp(*__last2, *__last1))
+ {
+   *--__result = ranges::iter_move(__last1);
+   if (__first1 == __last1)
+ {
+   ranges::move_backward(__first2, ++__last2, __result);
+   return;
+ }
+   --__last1;
+ }
+   else
+ {
+   *--__result = ranges::iter_move(__last2);
+   if (__first2 == __last2)
+ return;
+   --__last2;
+ }
+ }
+  }
+
+template
+  _Iter1
+  __rotate_adaptive(_Iter1 __first, _Iter1 __middle, _Iter1 __last,
+   iter_difference_t<_Iter1> __len1,
+   iter_difference_t<_Iter1> __len2,
+   _Iter2 __buffer,
+   iter_difference_t<_Iter1> __buffer_size)
+  {
+   _Iter2 __buffer_end;
+   if (__len1 > __len2 && __len2 <= __buffer_size)
+ {
+   if (__len2)
+ {
+   __buffer_end = ranges::move(__middle, __last, __buffer).out;
+   ranges::move_backward(__first, __middle, __last);
+   return ranges::move(__buffer, __buffer_end, __first).out;
+ }
+   else
+ return __first;
+ }
+   else if (__len1 <= __buffer_size)
+ {
+   if (__len1)
+ {
+   __buffer_end = ranges::move(__first, __middle, __buffer).out;
+   ranges::move(__middle, __last, __first);
+   return ranges::move_backward(__buffer, __buffer_end, 
__last).out;
+ }
+   else
+ return __last;
+ }
+   else
+ return ranges::rotate(__first, __middle, __last).begin();
+  }
+
+template
+  void
+  __merge_adaptive(_Iter 

[gcc r16-1741] libstdc++: Directly implement ranges::sort [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:92417c387365033cac4fff7ec8da2b42bd75dfba

commit r16-1741-g92417c387365033cac4fff7ec8da2b42bd75dfba
Author: Patrick Palka 
Date:   Fri Jun 27 13:53:06 2025 -0400

libstdc++: Directly implement ranges::sort [PR100795]

As with the previous patch, this patch reimplements ranges::sort
directly instead of incorrectly forwarding to std::sort.  In addition to
the compatibility changes listed in the previous patch we also:

  - use ranges::iter_swap instead of std::iter_swap
  - use ranges::move_backward instead of std::move_backward
  - use __bit_width and __to_unsigned_like instead of __lg

PR libstdc++/100795
PR libstdc++/118209

libstdc++-v3/ChangeLog:

* include/bits/max_size_type.h (__bit_width): New explicit
specialization for __max_size_type.
* include/bits/ranges_algo.h (__detail::__move_median_to_first):
New, based on the stl_algo.h implementation.
(__detail::__unguarded_liner_insert): Likewise.
(__detail::__insertion_sort): Likewise.
(__detail::__sort_threshold): Likewise.
(__detail::__unguarded_insertion_sort): Likewise.
(__detail::__final_insertion_sort): Likewise.
(__detail::__unguarded_partition): Likewise.
(__detail::__unguarded_partition_pivot): Likewise.
(__detail::__heap_select): Likewise.
(__detail::__partial_sort): Likewise.
(__detail::__introsort_loop): Likewise.
(__sort_fn::operator()): Reimplement in terms of the above.
* testsuite/25_algorithms/sort/118209.cc: New test.
* testsuite/25_algorithms/sort/constrained.cc (test03): New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/max_size_type.h  |  11 ++
 libstdc++-v3/include/bits/ranges_algo.h| 168 -
 .../testsuite/25_algorithms/sort/118209.cc |  23 +++
 .../testsuite/25_algorithms/sort/constrained.cc|  31 
 4 files changed, 229 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/max_size_type.h 
b/libstdc++-v3/include/bits/max_size_type.h
index e602b1b4bee5..73a6d141d5bc 100644
--- a/libstdc++-v3/include/bits/max_size_type.h
+++ b/libstdc++-v3/include/bits/max_size_type.h
@@ -36,6 +36,7 @@
 
 #if __cplusplus > 201703L && __cpp_lib_concepts
 #include 
+#include  // __bit_width
 #include 
 
 // This header implements unsigned and signed integer-class types (as per
@@ -818,6 +819,16 @@ namespace ranges
   { return min(); }
 };
 
+  template<>
+  inline constexpr int
+  __bit_width(ranges::__detail::__max_size_type __x) noexcept
+  {
+if (__x._M_msb)
+  return numeric_limits::digits;
+else
+  return std::__bit_width(__x._M_val);
+  }
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index d13729a83f72..de935dde4f70 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -32,6 +32,7 @@
 
 #if __cplusplus > 201703L
 
+#include  // __bit_width
 #if __cplusplus > 202002L
 #include 
 #endif
@@ -2200,6 +2201,154 @@ namespace ranges
 
   inline constexpr __is_heap_fn is_heap{};
 
+  namespace __detail
+  {
+template
+  constexpr void
+  __move_median_to_first(_Iter __result, _Iter __a, _Iter __b, _Iter __c,
+_Comp __comp)
+  {
+   if (__comp(*__a, *__b))
+ {
+   if (__comp(*__b, *__c))
+ ranges::iter_swap(__result, __b);
+   else if (__comp(*__a, *__c))
+ ranges::iter_swap(__result, __c);
+   else
+ ranges::iter_swap(__result, __a);
+ }
+   else if (__comp(*__a, *__c))
+ ranges::iter_swap(__result, __a);
+   else if (__comp(*__b, *__c))
+ ranges::iter_swap(__result, __c);
+   else
+ ranges::iter_swap(__result, __b);
+  }
+
+template
+  constexpr void
+  __unguarded_linear_insert(_Iter __last, _Comp __comp)
+  {
+   iter_value_t<_Iter> __val = ranges::iter_move(__last);
+   _Iter __next = __last;
+   --__next;
+   while (__comp(__val, *__next))
+ {
+   *__last = ranges::iter_move(__next);
+   __last = __next;
+   --__next;
+ }
+   *__last = std::move(__val);
+  }
+
+template
+  constexpr void
+  __insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
+  {
+   if (__first == __last)
+ return;
+
+   for (_Iter __i = __first + 1; __i != __last; ++__i)
+ {
+   if (__comp(*__i, *__first))
+ {
+   iter_value_t<_Iter> __val = ranges::iter_move(__i);
+   ranges::move_backward(__first, __i, __i + 1);
+   *__first = std::m

[gcc r16-1740] libstdc++: Directly implement ranges::heap algos [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:a148b0377805376e33f36bed0e48a401a6dd82c6

commit r16-1740-ga148b0377805376e33f36bed0e48a401a6dd82c6
Author: Patrick Palka 
Date:   Fri Jun 27 13:52:56 2025 -0400

libstdc++: Directly implement ranges::heap algos [PR100795]

ranges::push_heap, ranges::pop_heap, ranges::make_heap and
ranges::sort_heap are currently defined in terms of the corresponding
STL-style algorithms, but this is incorrect because the STL-style
algorithms rely on the legacy iterator system, and so misbehave when
passed a narrowly C++20 random access iterator.  The other ranges heap
algos, ranges::is_heap and ranges::is_heap_until, are implemented
directly already and have no known issues.

This patch reimplements these ranges:: algos directly instead, based
closely on the legacy stl_heap.h implementation, with the following
changes for compatibility with the C++20 iterator system:

  - handle non-common ranges by computing the corresponding end iterator
  - use ranges::iter_move instead of std::move(*iter)
  - use iter_value_t / iter_difference_t instead of iterator_traits

Besides these changes, the implementation of these algorithms is
intended to mirror the stl_heap.h implementations, for ease of
maintenance and review.

Note that we don't explicitly pass the projection function throughout,
instead we just create and pass a composite predicate via __make_comp_proj.

PR libstdc++/100795

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__detail::__push_heap): New,
based on the stl_heap.h implementation.
(__push_heap_fn::operator()): Reimplement in terms of the above.
(__detail::__adjust_heap): New, based on the stl_heap.h
implementation.
(__deatil::__pop_heap): Likewise.
(__pop_heap_fn::operator()): Reimplement in terms of the above.
(__make_heap_fn::operator()): Likewise.
(__sort_heap_fn::operator()): Likewise.
* testsuite/25_algorithms/heap/constrained.cc (test03): New
test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 140 ++---
 .../testsuite/25_algorithms/heap/constrained.cc|  46 +++
 2 files changed, 170 insertions(+), 16 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 5aca6e8d864d..d13729a83f72 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1913,6 +1913,28 @@ namespace ranges
 
   inline constexpr __shuffle_fn shuffle{};
 
+  namespace __detail
+  {
+template
+  constexpr void
+  __push_heap(_Iter __first,
+ iter_difference_t<_Iter> __holeIndex,
+ iter_difference_t<_Iter> __topIndex,
+ iter_value_t<_Iter> __value,
+ _Comp __comp)
+  {
+   auto __parent = (__holeIndex - 1) / 2;
+   while (__holeIndex > __topIndex
+  && __comp(*(__first + __parent), __value))
+ {
+   *(__first + __holeIndex) = ranges::iter_move(__first + __parent);
+   __holeIndex = __parent;
+   __parent = (__holeIndex - 1) / 2;
+ }
+   *(__first + __holeIndex) = std::move(__value);
+  }
+  } // namespace __detail
+
   struct __push_heap_fn
   {
 template _Sent,
@@ -1922,10 +1944,17 @@ namespace ranges
   operator()(_Iter __first, _Sent __last,
 _Comp __comp = {}, _Proj __proj = {}) const
   {
-   auto __lasti = ranges::next(__first, __last);
-   std::push_heap(__first, __lasti,
-  __detail::__make_comp_proj(__comp, __proj));
-   return __lasti;
+   if constexpr (!same_as<_Iter, _Sent>)
+ return (*this)(__first, ranges::next(__first, __last),
+std::move(__comp), std::move(__proj));
+   else
+ {
+   auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+   __detail::__push_heap(__first, (__last - __first) - 1,
+ 0, ranges::iter_move(__last - 1),
+ __comp_proj);
+   return __last;
+ }
   }
 
 template
+  constexpr void
+  __adjust_heap(_Iter __first,
+   iter_difference_t<_Iter> __holeIndex,
+   iter_difference_t<_Iter> __len,
+   iter_value_t<_Iter> __value,
+   _Comp __comp)
+  {
+   auto __topIndex = __holeIndex;
+   auto __secondChild = __holeIndex;
+   while (__secondChild < (__len - 1) / 2)
+ {
+   __secondChild = 2 * (__secondChild + 1);
+   if (__comp(*(__first + __secondChild),
+  *(__first + (__secondChild - 1
+ __secondChild--;
+  

[gcc r16-1746] libstdc++: Directly implement ranges::sample [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:4fc387e2f6990986d72b023ee44b4e0030903247

commit r16-1746-g4fc387e2f6990986d72b023ee44b4e0030903247
Author: Patrick Palka 
Date:   Fri Jun 27 13:53:37 2025 -0400

libstdc++: Directly implement ranges::sample [PR100795]

PR libstdc++/100795

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__sample_fn::operator()):
Reimplement the forward_iterator branch directly, based
on the stl_algo.h implementation.  Add explicit cast to
_Out's difference_type in the !forward_iterator branch.
* testsuite/25_algorithms/sample/constrained.cc (test02):
New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 70 +++---
 .../testsuite/25_algorithms/sample/constrained.cc  | 26 
 2 files changed, 89 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 4d10eaa7f83d..972d18cbdf06 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1839,14 +1839,70 @@ namespace ranges
   operator()(_Iter __first, _Sent __last, _Out __out,
 iter_difference_t<_Iter> __n, _Gen&& __g) const
   {
+   // FIXME: Correctly handle integer-class difference types.
if constexpr (forward_iterator<_Iter>)
  {
-   // FIXME: Forwarding to std::sample here requires computing __lasti
-   // which may take linear time.
-   auto __lasti = ranges::next(__first, __last);
-   return _GLIBCXX_STD_A::
- sample(std::move(__first), std::move(__lasti), std::move(__out),
-__n, std::forward<_Gen>(__g));
+   using _Size = iter_difference_t<_Iter>;
+   using __distrib_type = uniform_int_distribution<_Size>;
+   using __param_type = typename __distrib_type::param_type;
+   using _USize = __detail::__make_unsigned_like_t<_Size>;
+   using __uc_type
+ = common_type_t::result_type, 
_USize>;
+
+   if (__first == __last)
+ return __out;
+
+   __distrib_type __d{};
+   _Size __unsampled_sz = ranges::distance(__first, __last);
+   __n = std::min(__n, __unsampled_sz);
+
+   // If possible, we use __gen_two_uniform_ints to efficiently produce
+   // two random numbers using a single distribution invocation:
+
+   const __uc_type __urngrange = __g.max() - __g.min();
+   if (__urngrange / __uc_type(__unsampled_sz) >= 
__uc_type(__unsampled_sz))
+ // I.e. (__urngrange >= __unsampled_sz * __unsampled_sz) but 
without
+ // wrapping issues.
+ {
+   while (__n != 0 && __unsampled_sz >= 2)
+ {
+   const pair<_Size, _Size> __p =
+ __gen_two_uniform_ints(__unsampled_sz, __unsampled_sz - 
1, __g);
+
+   --__unsampled_sz;
+   if (__p.first < __n)
+ {
+   *__out = *__first;
+   ++__out;
+   --__n;
+ }
+
+   ++__first;
+
+   if (__n == 0) break;
+
+   --__unsampled_sz;
+   if (__p.second < __n)
+ {
+   *__out = *__first;
+   ++__out;
+   --__n;
+ }
+
+   ++__first;
+ }
+ }
+
+   // The loop above is otherwise equivalent to this one-at-a-time 
version:
+
+   for (; __n != 0; ++__first)
+ if (__d(__g, __param_type{0, --__unsampled_sz}) < __n)
+   {
+ *__out = *__first;
+ ++__out;
+ --__n;
+   }
+   return __out;
  }
else
  {
@@ -1867,7 +1923,7 @@ namespace ranges
if (__k < __n)
  __out[__k] = *__first;
  }
-   return __out + __sample_sz;
+   return __out + iter_difference_t<_Out>(__sample_sz);
  }
   }
 
diff --git a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
index b9945b164903..0ec3e0b0 100644
--- a/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/sample/constrained.cc
@@ -20,6 +20,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -59,9 +60,34 @@ test01()
 }
 }
 
+void
+test02()
+{
+  // PR libstdc++/100795 - ranges::sample should not use std::sample
+#if 0 // FIXME: ranges::sample rejects integer-class difference types.
+#if __SIZEOF_INT128__
+  auto v = std::views::iota(__int128(0), __int128(20));
+#else
+  auto v = std::views::iota(0ll, 20ll);
+

[gcc r16-1747] libstdc++: Directly implement ranges::shuffle [PR100795]

2025-06-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:b4aadc60154c62425c36c61d23c7549d31fe1397

commit r16-1747-gb4aadc60154c62425c36c61d23c7549d31fe1397
Author: Patrick Palka 
Date:   Fri Jun 27 13:53:40 2025 -0400

libstdc++: Directly implement ranges::shuffle [PR100795]

PR libstdc++/100795

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (shuffle_fn::operator()):
Reimplement directly, based on the stl_algo.h implementation.
* testsuite/25_algorithms/shuffle/constrained.cc (test02):
New test.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 58 --
 .../testsuite/25_algorithms/shuffle/constrained.cc | 25 ++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 972d18cbdf06..2df730eabc8b 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1952,9 +1952,61 @@ namespace ranges
   _Iter
   operator()(_Iter __first, _Sent __last, _Gen&& __g) const
   {
-   auto __lasti = ranges::next(__first, __last);
-   std::shuffle(std::move(__first), __lasti, std::forward<_Gen>(__g));
-   return __lasti;
+   // FIXME: Correctly handle integer-class difference types.
+   if (__first == __last)
+ return __first;
+
+   using _DistanceType = iter_difference_t<_Iter>;
+   using __ud_type = __detail::__make_unsigned_like_t<_DistanceType>;
+   using __distr_type = std::uniform_int_distribution<__ud_type>;
+   using __p_type = typename __distr_type::param_type;
+
+   using __uc_type
+ = common_type_t::result_type, 
__ud_type>;
+
+   const __uc_type __urngrange = __g.max() - __g.min();
+   const __uc_type __urange = __uc_type(__last - __first);
+
+   if (__urngrange / __urange >= __urange)
+ // I.e. (__urngrange >= __urange * __urange) but without wrap issues.
+ {
+   _Iter __i = __first + 1;
+
+   // Since we know the range isn't empty, an even number of elements
+   // means an uneven number of elements /to swap/, in which case we
+   // do the first one up front:
+
+   if ((__urange % 2) == 0)
+ {
+   __distr_type __d{0, 1};
+   ranges::iter_swap(__i++, __first + __d(__g));
+ }
+
+   // Now we know that __last - __i is even, so we do the rest in 
pairs,
+   // using a single distribution invocation to produce swap positions
+   // for two successive elements at a time:
+
+   while (__i != __last)
+ {
+   const __uc_type __swap_range = __uc_type(__i - __first) + 1;
+
+   const pair<__uc_type, __uc_type> __pospos =
+ __gen_two_uniform_ints(__swap_range, __swap_range + 1, __g);
+
+   ranges::iter_swap(__i++, __first + __pospos.first);
+   ranges::iter_swap(__i++, __first + __pospos.second);
+ }
+
+   return __i;
+ }
+
+   __distr_type __d;
+
+   _Iter __i = __first + 1;
+   for (; __i != __last; ++__i)
+ ranges::iter_swap(__i, __first + __d(__g, __p_type(0, __i - 
__first)));
+
+   return __i;
   }
 
 template
diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc 
b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
index d0977a292fee..70c6bdfc3d9e 100644
--- a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
@@ -20,6 +20,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -62,8 +63,32 @@ test01()
 }
 }
 
+void
+test02()
+{
+  // PR libstdc++/100795 - ranges::shuffle should not use std::shuffle directly
+#if 0 // FIXME: ranges::shuffle rejects integer-class difference types.
+#if __SIZEOF_INT128__
+  auto v = std::views::iota(__int128(0), __int128(20));
+#else
+  auto v = std::views::iota(0ll, 20ll);
+#endif
+#else
+  auto v = std::views::iota(0, 20);
+#endif
+
+  int storage[20] = {2,5,4,3,1,6,7,9,10,8,11,14,12,13,15,16,18,0,19,17};
+  auto w = v | std::views::transform([&](auto i) -> int& { return storage[i]; 
});
+  using type = decltype(w);
+  static_assert( std::ranges::random_access_range );
+
+  std::ranlux48_base g;
+  ranges::shuffle(w, g);
+}
+
 int
 main()
 {
   test01();
+  test02();
 }


[gcc r15-9752] libstdc++: Compare keys and values separately in flat_map::operator==

2025-06-01 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:771fcb9fe9b3fce8336a797c03c399a63e11eb21

commit r15-9752-g771fcb9fe9b3fce8336a797c03c399a63e11eb21
Author: Patrick Palka 
Date:   Thu May 29 10:12:23 2025 -0400

libstdc++: Compare keys and values separately in flat_map::operator==

Instead of effectively doing a zipped comparison of the keys and values,
compare them separately to leverage the underlying containers' optimized
equality implementations.

libstdc++-v3/ChangeLog:

* include/std/flat_map (_Flat_map_impl::operator==): Compare
keys and values separately.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit ad96f0344adfc847874b34b43f30371979ae9963)

Diff:
---
 libstdc++-v3/include/std/flat_map | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/flat_map 
b/libstdc++-v3/include/std/flat_map
index cec7f36cff9f..4bd4963c2ad7 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -873,7 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   [[nodiscard]]
   friend bool
   operator==(const _Derived& __x, const _Derived& __y)
-  { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
+  {
+   return __x._M_cont.keys == __y._M_cont.keys
+ && __x._M_cont.values == __y._M_cont.values;
+  }
 
   template
[[nodiscard]]


[gcc r16-958] libstdc++: Compare keys and values separately in flat_map::operator==

2025-05-29 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:ad96f0344adfc847874b34b43f30371979ae9963

commit r16-958-gad96f0344adfc847874b34b43f30371979ae9963
Author: Patrick Palka 
Date:   Thu May 29 10:12:23 2025 -0400

libstdc++: Compare keys and values separately in flat_map::operator==

Instead of effectively doing a zipped comparison of the keys and values,
compare them separately to leverage the underlying containers' optimized
equality implementations.

libstdc++-v3/ChangeLog:

* include/std/flat_map (_Flat_map_impl::operator==): Compare
keys and values separately.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/flat_map | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/flat_map 
b/libstdc++-v3/include/std/flat_map
index cec7f36cff9f..4bd4963c2ad7 100644
--- a/libstdc++-v3/include/std/flat_map
+++ b/libstdc++-v3/include/std/flat_map
@@ -873,7 +873,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   [[nodiscard]]
   friend bool
   operator==(const _Derived& __x, const _Derived& __y)
-  { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
+  {
+   return __x._M_cont.keys == __y._M_cont.keys
+ && __x._M_cont.values == __y._M_cont.values;
+  }
 
   template
[[nodiscard]]


[gcc r16-1502] libstdc++: Optimize __make_comp/pred_proj for empty/scalar types

2025-06-13 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:5e8168a659ecc63804984d20365b4df401d9675b

commit r16-1502-g5e8168a659ecc63804984d20365b4df401d9675b
Author: Patrick Palka 
Date:   Fri Jun 13 11:03:19 2025 -0400

libstdc++: Optimize __make_comp/pred_proj for empty/scalar types

When creating a composite comparator/predicate that invokes a given
projection function, we don't need to capture a scalar (such as a
function pointer or member pointer) or empty object by reference,
instead capture it by value and use [[no_unique_address]] to elide
its storage (in the empty case).  This makes using __make_comp_proj
zero-cost in the common case where both functions are empty/scalars.

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__detail::__by_ref_or_value_fn): New.
(__detail::_Comp_proj): New.
(__detail::__make_comp_proj): Use it instead.
(__detail::_Pred_proj): New.
(__detail::__make_pred_proj): Use it instead.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h | 64 -
 1 file changed, 48 insertions(+), 16 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index a62c3cd3954d..5aca6e8d864d 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -47,28 +47,60 @@ namespace ranges
 {
   namespace __detail
   {
+template
+  using __by_ref_or_value_fn
+   = __conditional_t || is_empty_v<_Fp>, _Fp, _Fp&>;
+
 template
-  constexpr auto
+  struct _Comp_proj
+  {
+   [[no_unique_address]] __by_ref_or_value_fn<_Comp> _M_comp;
+   [[no_unique_address]] __by_ref_or_value_fn<_Proj> _M_proj;
+
+   constexpr
+   _Comp_proj(_Comp& __comp, _Proj& __proj)
+   : _M_comp(__comp), _M_proj(__proj)
+   { }
+
+   template
+ constexpr bool
+ operator()(_Tp&& __x, _Up&& __y)
+ {
+   return std::__invoke(_M_comp,
+std::__invoke(_M_proj, std::forward<_Tp>(__x)),
+std::__invoke(_M_proj, 
std::forward<_Up>(__y)));
+ }
+  };
+
+template
+  constexpr _Comp_proj<_Comp, _Proj>
   __make_comp_proj(_Comp& __comp, _Proj& __proj)
+  { return {__comp, __proj}; }
+
+template
+  struct _Pred_proj
   {
-   return [&] (auto&& __lhs, auto&& __rhs) -> bool {
- using _TL = decltype(__lhs);
- using _TR = decltype(__rhs);
- return std::__invoke(__comp,
-  std::__invoke(__proj, std::forward<_TL>(__lhs)),
-  std::__invoke(__proj, std::forward<_TR>(__rhs)));
-   };
-  }
+   [[no_unique_address]] __by_ref_or_value_fn<_Pred> _M_pred;
+   [[no_unique_address]] __by_ref_or_value_fn<_Proj> _M_proj;
+
+   constexpr
+   _Pred_proj(_Pred& __pred, _Proj& __proj)
+   : _M_pred(__pred), _M_proj(__proj)
+   { }
+
+   template
+ constexpr bool
+ operator()(_Tp&& __x)
+ {
+   return std::__invoke(_M_pred,
+std::__invoke(_M_proj, 
std::forward<_Tp>(__x)));
+ }
+  };
 
 template
-  constexpr auto
+  constexpr _Pred_proj<_Pred, _Proj>
   __make_pred_proj(_Pred& __pred, _Proj& __proj)
-  {
-   return [&]  (_Tp&& __arg) -> bool {
- return std::__invoke(__pred,
-  std::__invoke(__proj, std::forward<_Tp>(__arg)));
-   };
-  }
+  { return {__pred, __proj}; }
   } // namespace __detail
 
   struct __all_of_fn


[gcc r16-700] libstdc++: Use __is_invocable/nothrow_invocable builtins more

2025-05-16 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:259154325688cbfe6d3b50e91dbd6b997a969d6d

commit r16-700-g259154325688cbfe6d3b50e91dbd6b997a969d6d
Author: Patrick Palka 
Date:   Fri May 16 13:06:04 2025 -0400

libstdc++: Use __is_invocable/nothrow_invocable builtins more

As a follow-up to r15-1253 and r15-1254 which made us use these builtins
in the standard std::is_invocable/nothrow_invocable class templates, let's
also use them directly in the standard variable templates and our internal
C++11 __is_invocable/nothrow_invocable class templates.

libstdc++-v3/ChangeLog:

* include/std/type_traits (__is_invocable): Define in terms of
corresponding builtin if available.
(__is_nothrow_invocable): Likewise.
(is_invocable_v): Likewise.
(is_nothrow_invocable_v): Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/type_traits | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/include/std/type_traits 
b/libstdc++-v3/include/std/type_traits
index 676cdf2d7e66..0601869266c9 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3212,7 +3212,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template
 struct __is_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+: __bool_constant<__is_invocable(_Fn, _ArgTypes...)>
+#else
 : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type
+#endif
 { };
 
   template
@@ -3263,8 +3267,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // __is_nothrow_invocable (std::is_nothrow_invocable for C++11)
   template
 struct __is_nothrow_invocable
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable)
+: __bool_constant<__is_nothrow_invocable(_Fn, _Args...)>
+#else
 : __and_<__is_invocable<_Fn, _Args...>,
  __call_is_nothrow_<_Fn, _Args...>>::type
+#endif
 { };
 
 #pragma GCC diagnostic push
@@ -3704,10 +3712,19 @@ template 
   inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value;
 #endif
 template
-  inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value;
+  inline constexpr bool is_invocable_v
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_invocable)
+= __is_invocable(_Fn, _Args...);
+#else
+= is_invocable<_Fn, _Args...>::value;
+#endif
 template
   inline constexpr bool is_nothrow_invocable_v
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_invocable)
+= __is_nothrow_invocable(_Fn, _Args...);
+#else
 = is_nothrow_invocable<_Fn, _Args...>::value;
+#endif
 template
   inline constexpr bool is_invocable_r_v
 = is_invocable_r<_Ret, _Fn, _Args...>::value;


[gcc r13-9710] libstdc++: Implement P2836R1 changes to const_iterator

2025-05-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:d6551d6d83edf3ee07eca4baeb0cc3f6050af645

commit r13-9710-gd6551d6d83edf3ee07eca4baeb0cc3f6050af645
Author: Patrick Palka 
Date:   Mon Jan 15 15:13:53 2024 -0500

libstdc++: Implement P2836R1 changes to const_iterator

libstdc++-v3/ChangeLog:

* include/bits/stl_iterator.h (const_iterator): Define conversion
operators as per P2836R1.
* include/std/ranges (__cpp_lib_ranges_as_const): Update value.
* include/std/version (__cpp_lib_ranges_as_const): Likewise.
* testsuite/24_iterators/const_iterator/1.cc (test04): New test.
* testsuite/std/ranges/adaptors/as_const/1.cc: Adjust expected
value of __cpp_lib_ranges_as_const.
* testsuite/std/ranges/version_c++23.cc: Likewise.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 731444b3c39e3dc3dd8778f430a38742861dcca1)

Diff:
---
 libstdc++-v3/include/bits/stl_iterator.h   | 12 
 libstdc++-v3/include/std/ranges|  2 +-
 libstdc++-v3/include/std/version   |  2 +-
 .../testsuite/24_iterators/const_iterator/1.cc | 22 ++
 .../testsuite/std/ranges/adaptors/as_const/1.cc|  2 +-
 libstdc++-v3/testsuite/std/ranges/version_c++23.cc |  2 +-
 6 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/bits/stl_iterator.h 
b/libstdc++-v3/include/bits/stl_iterator.h
index 68bb1023081a..a6b55500be98 100644
--- a/libstdc++-v3/include/bits/stl_iterator.h
+++ b/libstdc++-v3/include/bits/stl_iterator.h
@@ -2798,6 +2798,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   noexcept(noexcept(_M_current == __s))
   { return _M_current == __s; }
 
+template<__detail::__not_a_const_iterator _CIt>
+  requires __detail::__constant_iterator<_CIt> && convertible_to<_It, _CIt>
+constexpr
+operator _CIt() const&
+{ return _M_current; }
+
+template<__detail::__not_a_const_iterator _CIt>
+  requires __detail::__constant_iterator<_CIt> && convertible_to<_It, _CIt>
+constexpr
+operator _CIt() &&
+{ return std::move(_M_current); }
+
 constexpr bool
 operator<(const basic_const_iterator& __y) const
 noexcept(noexcept(_M_current < __y._M_current))
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 7bf4746973ff..daf3f32b808c 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -8953,7 +8953,7 @@ namespace views::__adaptor
 inline constexpr _Enumerate enumerate;
   }
 
-#define __cpp_lib_ranges_as_const 202207L
+#define __cpp_lib_ranges_as_const 202311L
 
   template
 requires input_range<_Vp>
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index ee515c4e66ca..7376f8eed4d4 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -341,7 +341,7 @@
 #define __cpp_lib_ranges_stride 202207L
 #define __cpp_lib_ranges_cartesian_product 202207L
 #define __cpp_lib_ranges_as_rvalue 202207L
-#define __cpp_lib_ranges_as_const 202207L
+#define __cpp_lib_ranges_as_const 202311L
 #define __cpp_lib_ranges_enumerate 202302L
 #define __cpp_lib_ranges_contains 202207L
 #define __cpp_lib_ranges_iota 202202L
diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc 
b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
index 51befd295410..81e2e69ce39d 100644
--- a/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
+++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc
@@ -2,6 +2,7 @@
 // { dg-do run { target c++23 } }
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -98,6 +99,26 @@ test03()
 std::unreachable_sentinel_t> );
 }
 
+void
+test04()
+{
+  // Example from P2836R1
+  auto f = [](std::vector::const_iterator i) {};
+
+  auto v = std::vector();
+  {
+auto i1 = ranges::cbegin(v); // returns vector::const_iterator
+f(i1); // okay
+  }
+
+  auto t = v | std::views::take_while([](int const x) { return x < 100; });
+  {
+auto i2 = ranges::cbegin(t); // returns 
basic_const_iterator::iterator>
+f(i2); // was an error in C++23 before P2836R1
+f(std::move(i2)); // same
+  }
+}
+
 int
 main()
 {
@@ -137,4 +158,5 @@ main()
   test02, true>();
 
   test03();
+  test04();
 }
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index ac1be7440e47..7bafc752f50a 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -9,7 +9,7 @@
 #include 
 #include 
 
-#if __cpp_lib_ranges_as_const != 202207L
+#if __cpp_lib_ranges_as_const != 202311L
 # error "Feature-test macro __cpp_lib_ranges_as_const has wrong value in 
"
 #endif
 
diff --git a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc 
b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc
index e8342fa986a8.

[gcc r13-9712] libstdc++: Fix ref_view branch of views::as_const [PR119135]

2025-05-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:a56fdac95755175c760cf35a246414859746d4b3

commit r13-9712-ga56fdac95755175c760cf35a246414859746d4b3
Author: Patrick Palka 
Date:   Thu Mar 13 09:15:21 2025 -0400

libstdc++: Fix ref_view branch of views::as_const [PR119135]

Unlike for span and empty_view, the range_reference_t of
ref_view doesn't correspond to X.  This patch fixes the ref_view
branch of views::as_const to correctly query its underlying range
type X.

PR libstdc++/119135

libstdc++-v3/ChangeLog:

* include/std/ranges: Include .
(views::__detail::__is_ref_view): Replace with ...
(views::__detail::__is_constable_ref_view): ... this.
(views::_AsConst::operator()): Replace bogus use of element_type
in the ref_view branch.
* testsuite/std/ranges/adaptors/as_const/1.cc (test03): Extend
test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 
(cherry picked from commit 50359c0a44381edb6dbd9359ef2ebdadbcc3ed42)

Diff:
---
 libstdc++-v3/include/std/ranges  | 12 ++--
 libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc |  4 
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index dda61349c8fd..2735f1613dd1 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -46,6 +46,7 @@
 #include 
 #include 
 #if __cplusplus > 202002L
+#include 
 #include 
 #endif
 #include 
@@ -9018,10 +9019,11 @@ namespace views::__adaptor
 namespace __detail
 {
   template
-   inline constexpr bool __is_ref_view = false;
+   inline constexpr bool __is_constable_ref_view = false;
 
   template
-   inline constexpr bool __is_ref_view> = true;
+   inline constexpr bool __is_constable_ref_view>
+ = constant_range;
 
   template
concept __can_as_const_view = requires { 
as_const_view(std::declval<_Range>()); };
@@ -9043,10 +9045,8 @@ namespace views::__adaptor
  return views::empty;
else if constexpr (std::__detail::__is_span<_Tp>)
  return span(std::forward<_Range>(__r));
-   else if constexpr (__detail::__is_ref_view<_Tp>
-  && constant_range)
- return ref_view(static_cast
- (std::forward<_Range>(__r).base()));
+   else if constexpr (__detail::__is_constable_ref_view<_Tp>)
+ return ref_view(std::as_const(std::forward<_Range>(__r).base()));
else if constexpr (is_lvalue_reference_v<_Range>
   && constant_range
   && !view<_Tp>)
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc 
b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
index 7bafc752f50a..03814096fffc 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc
@@ -62,6 +62,10 @@ test03()
   std::vector v;
   std::same_as>>
 auto r = views::as_const(v);
+
+  // PR libstdc++/119135
+  std::same_as>>
+auto r2 = views::as_const(views::all(v));
 }
 
 int


[gcc r13-9711] libstdc++: Implement P2540R1 change to views::cartesian_product()

2025-05-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:d28b05bf576d4b5ebeda2a44430d2cb17e1fa027

commit r13-9711-gd28b05bf576d4b5ebeda2a44430d2cb17e1fa027
Author: Patrick Palka 
Date:   Tue Jan 16 21:20:12 2024 -0500

libstdc++: Implement P2540R1 change to views::cartesian_product()

This paper changes the identity element of views::cartesian_product to a
singleton range instead of an empty range.  It was approved alongside
the main cartesian_product paper P2374R4, but unfortunately was overlooked
when implementing the main paper.

libstdc++-v3/ChangeLog:

* include/std/ranges (views::_CartesianProduct::operator()):
Adjust identity case as per P2540R1.
* testsuite/std/ranges/cartesian_product/1.cc (test01):
Adjust expected result of the identity case.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit 98966f32f906303cd7d2e1c418f320c483e6dcbe)

Diff:
---
 libstdc++-v3/include/std/ranges  | 2 +-
 libstdc++-v3/testsuite/std/ranges/cartesian_product/1.cc | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index daf3f32b808c..dda61349c8fd 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -8549,7 +8549,7 @@ namespace views::__adaptor
operator() [[nodiscard]] (_Ts&&... __ts) const
{
  if constexpr (sizeof...(_Ts) == 0)
-   return views::empty>;
+   return views::single(tuple{});
  else
return 
cartesian_product_view...>(std::forward<_Ts>(__ts)...);
}
diff --git a/libstdc++-v3/testsuite/std/ranges/cartesian_product/1.cc 
b/libstdc++-v3/testsuite/std/ranges/cartesian_product/1.cc
index ef2ece4a1686..a44465fc7e55 100644
--- a/libstdc++-v3/testsuite/std/ranges/cartesian_product/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/cartesian_product/1.cc
@@ -23,9 +23,9 @@ test01()
   int w[] = {9};
 
   auto v0 = views::cartesian_product();
-  VERIFY( ranges::end(v0) - ranges::begin(v0) == 0 );
-  VERIFY( ranges::size(v0) == 0 );
-  VERIFY( ranges::empty(v0) );
+  VERIFY( ranges::end(v0) - ranges::begin(v0) == 1 );
+  VERIFY( ranges::size(v0) == 1 );
+  VERIFY( !ranges::empty(v0) );
 
   auto v1 = views::cartesian_product(x);
   VERIFY( ranges::end(v1) - ranges::begin(v1) == 3 );


[gcc r13-9716] libstdc++: Fix backported test [PR112490]

2025-05-27 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:c923901d9cd16b4105312a3319c245cbcb02bf83

commit r13-9716-gc923901d9cd16b4105312a3319c245cbcb02bf83
Author: Patrick Palka 
Date:   Tue May 27 17:49:30 2025 -0400

libstdc++: Fix backported test [PR112490]

On the 13 branch and older, C++ >= 20 tests need an explicit dg-options
directive specifying the -std flag, otherwise they won't run by default.

PR libstdc++/112490

libstdc++-v3/ChangeLog:

* testsuite/24_iterators/const_iterator/112490.cc: Add
dg-options directive.

Diff:
---
 libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc 
b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
index 9bb154847cff..e6e74eb675d4 100644
--- a/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
+++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/112490.cc
@@ -1,3 +1,4 @@
+// { dg-options "-std=gnu++23" }
 // { dg-do compile { target c++23 } }
 
 // PR libstdc++/112490 - infinite meta error in


[gcc r16-1106] libstdc++: Implement C++23 P1659R3 starts_with and ends_with

2025-06-04 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:6545e2f301cc1c276dd039e8739f7cc912ec5ae9

commit r16-1106-g6545e2f301cc1c276dd039e8739f7cc912ec5ae9
Author: Patrick Palka 
Date:   Wed Jun 4 10:29:47 2025 -0400

libstdc++: Implement C++23 P1659R3 starts_with and ends_with

This implements ranges::starts_with and ranges::ends_with from the C++23
paper P1659R3.  The corresponding_S_impl member functions take optional
optional size parameters __n1 and __n2 of the two ranges, where -1 means
the corresponding size is not known.

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (__starts_with_fn, starts_with):
Define.
(__ends_with_fn, ends_with): Define.
* include/bits/version.def (ranges_starts_ends_with): Define.
* include/bits/version.h: Regenerate.
* include/std/algorithm: Provide __cpp_lib_ranges_starts_ends_with.
* src/c++23/std.cc.in (ranges::starts_with): Export.
(ranges::ends_with): Export.
* testsuite/25_algorithms/ends_with/1.cc: New test.
* testsuite/25_algorithms/starts_with/1.cc: New test.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h| 248 +
 libstdc++-v3/include/bits/version.def  |   8 +
 libstdc++-v3/include/bits/version.h|  10 +
 libstdc++-v3/include/std/algorithm |   1 +
 libstdc++-v3/src/c++23/std.cc.in   |   4 +
 .../testsuite/25_algorithms/ends_with/1.cc | 165 ++
 .../testsuite/25_algorithms/starts_with/1.cc   | 158 +
 7 files changed, 594 insertions(+)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 7b1408452128..a62c3cd3954d 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -438,6 +438,254 @@ namespace ranges
 
   inline constexpr __search_n_fn search_n{};
 
+#if __glibcxx_ranges_starts_ends_with // C++ >= 23
+  struct __starts_with_fn
+  {
+template _Sent1,
+input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+typename _Pred = ranges::equal_to,
+typename _Proj1 = identity, typename _Proj2 = identity>
+  requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
+  constexpr bool
+  operator()(_Iter1 __first1, _Sent1 __last1,
+_Iter2 __first2, _Sent2 __last2, _Pred __pred = {},
+_Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+  {
+   iter_difference_t<_Iter1> __n1 = -1;
+   iter_difference_t<_Iter2> __n2 = -1;
+   if constexpr (sized_sentinel_for<_Sent1, _Iter1>)
+ __n1 = __last1 - __first1;
+   if constexpr (sized_sentinel_for<_Sent2, _Iter2>)
+ __n2 = __last2 - __first2;
+   return _S_impl(std::move(__first1), __last1, __n1,
+  std::move(__first2), __last2, __n2,
+  std::move(__pred),
+  std::move(__proj1), std::move(__proj2));
+  }
+
+template
+  requires indirectly_comparable, iterator_t<_Range2>,
+_Pred, _Proj1, _Proj2>
+  constexpr bool
+  operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {},
+_Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
+  {
+   range_difference_t<_Range1> __n1 = -1;
+   range_difference_t<_Range2> __n2 = -1;
+   if constexpr (sized_range<_Range1>)
+ __n1 = ranges::size(__r1);
+   if constexpr (sized_range<_Range2>)
+ __n2 = ranges::size(__r2);
+   return _S_impl(ranges::begin(__r1), ranges::end(__r1), __n1,
+  ranges::begin(__r2), ranges::end(__r2), __n2,
+  std::move(__pred),
+  std::move(__proj1), std::move(__proj2));
+  }
+
+  private:
+template
+  static constexpr bool
+  _S_impl(_Iter1 __first1, _Sent1 __last1, iter_difference_t<_Iter1> __n1,
+ _Iter2 __first2, _Sent2 __last2, iter_difference_t<_Iter2> __n2,
+ _Pred __pred, _Proj1 __proj1, _Proj2 __proj2)
+  {
+   if (__first2 == __last2) [[unlikely]]
+ return true;
+   else if (__n1 == -1 || __n2 == -1)
+ return ranges::mismatch(std::move(__first1), __last1,
+ std::move(__first2), __last2,
+ std::move(__pred),
+ std::move(__proj1), std::move(__proj2)).in2 
== __last2;
+   else if (__n1 < __n2)
+ return false;
+   else if constexpr (random_access_iterator<_Iter1>)
+ return ranges::equal(__first1, __first1 + 
iter_difference_t<_Iter1>(__n2),
+  std::move(__first2), __last2,
+  std::move(__pred),
+  std::move(__proj1), std::move(__proj

[gcc r16-1116] libstdc++: Implement P0849R8 auto(x) library changes

2025-06-04 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:e73a6d982789746d4bce9d0e595203f2a8dbbaa7

commit r16-1116-ge73a6d982789746d4bce9d0e595203f2a8dbbaa7
Author: Patrick Palka 
Date:   Wed Jun 4 14:55:40 2025 -0400

libstdc++: Implement P0849R8 auto(x) library changes

This implements the library changes in P0849R8 "auto(x): decay-copy
in the language" which consist of replacing most uses of the
exposition-only function decay-copy with auto(x) throughout the library
wording.  We implement this as a DR against C++20 since there should be
no behavior change in practice (especially in light of LWG 3724 which
makes decay-copy SFINAE-friendly).

The main difference between decay-copy and auto(x) is that decay-copy
materializes its argument unlike auto(x), and so the latter is a no-op
when its argument is a prvalue.  Effectively the former could introduce
an unnecessary move constructor call in some contexts.  In C++20 and
earlier we could emulate auto(x) with decay_t(x).

After this paper the only remaining uses of decay-copy in the standard
are in the specification of some range adaptors.  In our implementation
of those range adaptors I believe decay-copy is already implied which is
why we don't use __decay_copy explicitly there.  So since it's apparently
no longer needed this patch goes ahead and removes __decay_copy.

libstdc++-v3/ChangeLog:

* include/bits/c++config (_GLIBCXX_AUTO_CAST): Define.
* include/bits/iterator_concepts.h (_Decay_copy, __decay_copy):
Remove.
(__member_begin, __adl_begin): Use _GLIBCXX_AUTO_CAST instead of
__decay_copy as per P0849R8.
* include/bits/ranges_base.h (_Begin): Likewise.
(__member_end, __adl_end, _End): Likewise.
(__member_rbegin, __adl_rbegin, _RBegin): Likewise.
(__member_rend, __adl_rend, _Rend): Likewise.
(__member_size, __adl_size, _Size): Likewise.
(_Data): Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/c++config   |  6 
 libstdc++-v3/include/bits/iterator_concepts.h | 13 ++---
 libstdc++-v3/include/bits/ranges_base.h   | 40 +--
 3 files changed, 28 insertions(+), 31 deletions(-)

diff --git a/libstdc++-v3/include/bits/c++config 
b/libstdc++-v3/include/bits/c++config
index 676f5eecbbb6..eec3a4a499dd 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -273,6 +273,12 @@
 #define _GLIBCXX_NOEXCEPT_QUAL
 #endif
 
+#if __cpp_auto_cast
+# define _GLIBCXX_AUTO_CAST(X) auto(X)
+#else
+# define _GLIBCXX_AUTO_CAST(X) ::std::__decay_t(X)
+#endif
+
 // Macro for extern template, ie controlling template linkage via use
 // of extern keyword on template declaration. As documented in the g++
 // manual, it inhibits all implicit instantiations and is used
diff --git a/libstdc++-v3/include/bits/iterator_concepts.h 
b/libstdc++-v3/include/bits/iterator_concepts.h
index 3b73ff9b6b59..d31e4f145107 100644
--- a/libstdc++-v3/include/bits/iterator_concepts.h
+++ b/libstdc++-v3/include/bits/iterator_concepts.h
@@ -1022,19 +1022,10 @@ namespace ranges
   {
 using std::__detail::__class_or_enum;
 
-struct _Decay_copy final
-{
-  template
-   constexpr decay_t<_Tp>
-   operator()(_Tp&& __t) const
-   noexcept(is_nothrow_convertible_v<_Tp, decay_t<_Tp>>)
-   { return std::forward<_Tp>(__t); }
-} inline constexpr __decay_copy{};
-
 template
   concept __member_begin = requires(_Tp& __t)
{
- { __decay_copy(__t.begin()) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
};
 
 // Poison pill so that unqualified lookup doesn't find std::begin.
@@ -1044,7 +1035,7 @@ namespace ranges
   concept __adl_begin = __class_or_enum>
&& requires(_Tp& __t)
{
- { __decay_copy(begin(__t)) } -> input_or_output_iterator;
+ { _GLIBCXX_AUTO_CAST(begin(__t)) } -> input_or_output_iterator;
};
 
 // Simplified version of std::ranges::begin that only supports lvalues,
diff --git a/libstdc++-v3/include/bits/ranges_base.h 
b/libstdc++-v3/include/bits/ranges_base.h
index dde164988569..c09f7292067d 100644
--- a/libstdc++-v3/include/bits/ranges_base.h
+++ b/libstdc++-v3/include/bits/ranges_base.h
@@ -119,9 +119,9 @@ namespace ranges
  if constexpr (is_array_v>)
return true;
  else if constexpr (__member_begin<_Tp>)
-   return noexcept(__decay_copy(std::declval<_Tp&>().begin()));
+   return noexcept(_GLIBCXX_AUTO_CAST(std::declval<_Tp&>().begin()));
  else
-   return noexcept(__decay_copy(begin(std::declval<_Tp&>(;
+   return noexcept(_GLIBCXX_AUTO_CAST(begin(std::declval<_Tp&>(;
}
 
 public:
@@ -146,7 +146,7 @@ namespace ranges
 template
   concep

[gcc r16-3576] libstdc++: Conditionalize LWG 3569 changes to join_view

2025-09-04 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:7f7f1878eedd8093d382e1e7b74649d7e97d5918

commit r16-3576-g7f7f1878eedd8093d382e1e7b74649d7e97d5918
Author: Patrick Palka 
Date:   Thu Sep 4 09:57:36 2025 -0400

libstdc++: Conditionalize LWG 3569 changes to join_view

LWG 3569 adjusted join_view's iterator specification to handle non
default-constructible iterators by wrapping the corresponding data member
in std::optional, which we followed suit in r13-2649-g7aa80c82ecf3a3.

But this wrapping is unnecessary for iterators that are already
default-constructible.  Rather than unconditionally using std::optional
here, which introduces time/space overhead, this patch conditionalizes
our LWG 3569 changes on the iterator in question being non-forward (and
thus non default-constructible).  We check forwardness instead of
default-constructibility in order to accommodate input-only iterators
that satisfy but do not model default_initializable, e.g. whose default
constructor is underconstrained.

libstdc++-v3/ChangeLog:

* include/std/ranges (join_view::_Iterator::_M_satisfy):
Adjust to handle non-std::optional _M_inner as per before LWG 3569.
(join_view::_Iterator::_M_get_inner): New.
(join_view::_Iterator::_M_inner): Don't wrap in std::optional if
the iterator is forward.  Initialize.
(join_view::_Iterator::operator*): Use _M_get_inner instead
of *_M_inner.
(join_view::_Iterator::operator++): Likewise.
(join_view::_Iterator::iter_move): Likewise.
(join_view::_Iterator::iter_swap): Likewise.

Reviewed-by: Tomasz Kamiński 
Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/std/ranges | 49 +++--
 1 file changed, 37 insertions(+), 12 deletions(-)

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 156d12b31ba1..bae50d06ca81 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -2889,7 +2889,12 @@ namespace views::__adaptor
  }
 
if constexpr (_S_ref_is_glvalue)
- _M_inner.reset();
+ {
+   if constexpr (forward_iterator<_Inner_iter>)
+ _M_inner = _Inner_iter();
+   else
+ _M_inner.reset();
+ }
  }
 
  static constexpr auto
@@ -2929,6 +2934,24 @@ namespace views::__adaptor
  return *_M_parent->_M_outer;
  }
 
+ constexpr _Inner_iter&
+ _M_get_inner()
+ {
+   if constexpr (forward_iterator<_Inner_iter>)
+ return _M_inner;
+   else
+ return *_M_inner;
+ }
+
+ constexpr const _Inner_iter&
+ _M_get_inner() const
+ {
+   if constexpr (forward_iterator<_Inner_iter>)
+ return _M_inner;
+   else
+ return *_M_inner;
+ }
+
  constexpr
  _Iterator(_Parent* __parent, _Outer_iter __outer) requires 
forward_range<_Base>
: _M_outer(std::move(__outer)), _M_parent(__parent)
@@ -2942,7 +2965,9 @@ namespace views::__adaptor
  [[no_unique_address]]
__detail::__maybe_present_t, _Outer_iter> 
_M_outer
  = decltype(_M_outer)();
- optional<_Inner_iter> _M_inner;
+ __conditional_t,
+ _Inner_iter, optional<_Inner_iter>> _M_inner
+   = decltype(_M_inner)();
  _Parent* _M_parent = nullptr;
 
public:
@@ -2966,7 +2991,7 @@ namespace views::__adaptor
 
  constexpr decltype(auto)
  operator*() const
- { return **_M_inner; }
+ { return *_M_get_inner(); }
 
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 3500. join_view::iterator::operator->() is bogus
@@ -2974,7 +2999,7 @@ namespace views::__adaptor
  operator->() const
requires __detail::__has_arrow<_Inner_iter>
  && copyable<_Inner_iter>
- { return *_M_inner; }
+ { return _M_get_inner(); }
 
  constexpr _Iterator&
  operator++()
@@ -2985,7 +3010,7 @@ namespace views::__adaptor
  else
return *_M_parent->_M_inner;
}();
-   if (++*_M_inner == ranges::end(__inner_range))
+   if (++_M_get_inner() == ranges::end(__inner_range))
  {
++_M_get_outer();
_M_satisfy();
@@ -3015,9 +3040,9 @@ namespace views::__adaptor
  {
if (_M_outer == ranges::end(_M_parent->_M_base))
  _M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer));
-   while (*_M_inner == ranges::begin(__detail::__as_lvalue(*_M_outer)))
- *_M_inner = ranges::end(__detail::__as_lvalue(*--_M_outer));
-   --*_M_inner;
+   while (_M_get_inner() == 
ranges::begin(__detail::__as_lvalue(*_M_outer

[gcc r15-10340] libstdc++: Explicitly pass -Wsystem-headers in tests that need it

2025-09-18 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:2da81100da46ad89ec8c2dacca8a20632aa1c5de

commit r15-10340-g2da81100da46ad89ec8c2dacca8a20632aa1c5de
Author: Patrick Palka 
Date:   Tue Sep 16 20:59:10 2025 -0400

libstdc++: Explicitly pass -Wsystem-headers in tests that need it

When running libstdc++ tests using an installed gcc (as opposed to an
in-tree gcc), we naturally use system stdlib headers instead of the
in-tree headers.  But warnings from within system headers are suppressed
by default, so tests that check for such warnings spuriously fail in such
a setup.  This patch makes us compile such tests with -Wsystem-headers so
that they consistently pass.

libstdc++-v3/ChangeLog:

* testsuite/20_util/bind/dangling_ref.cc: Compile with
-Wsystem-headers.
* testsuite/20_util/ratio/operations/ops_overflow_neg.cc: Likewise.
* testsuite/20_util/unique_ptr/lwg4148.cc: Likewise.
* testsuite/29_atomics/atomic/operators/pointer_partial_void.cc:
Likewise.
* testsuite/30_threads/packaged_task/cons/dangling_ref.cc:
Likewise.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit e690b97761e18daccb4fff0151c97c1d0115b55f)

Diff:
---
 libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc | 1 +
 libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc | 2 +-
 libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc| 1 +
 .../testsuite/29_atomics/atomic/operators/pointer_partial_void.cc   | 1 +
 libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc| 1 +
 5 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc 
b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
index 17e7b21c45cb..32af0a27b8fe 100644
--- a/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
+++ b/libstdc++-v3/testsuite/20_util/bind/dangling_ref.cc
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
 #include 
 
 int f();
diff --git 
a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc 
b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
index 5eff8e31f82a..368866a63313 100644
--- a/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/ratio/operations/ops_overflow_neg.cc
@@ -1,6 +1,6 @@
 // { dg-do compile { target c++11 } }
 // { dg-require-cstdint "" }
-
+// { dg-additional-options "-Wsystem-headers" }
 // 2008-07-03 Chris Fairles 
 
 // Copyright (C) 2008-2025 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc 
b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
index c70d7a60631b..f5697e4e4021 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/lwg4148.cc
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
 
 // LWG 4148. unique_ptr::operator* should not allow dangling references
 
diff --git 
a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc 
b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
index e959418a1c3c..1e2f71e9c628 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/operators/pointer_partial_void.cc
@@ -1,6 +1,7 @@
 // { dg-do run { target { c++11_only || c++14_only } } }
 // { dg-require-atomic-builtins "" }
 // { dg-require-effective-target hosted }
+// { dg-additional-options "-Wsystem-headers" }
 
 // Copyright (C) 2012-2025 Free Software Foundation, Inc.
 //
diff --git 
a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc 
b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
index 51c6ade91c36..83411c7024e9 100644
--- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
+++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/dangling_ref.cc
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wsystem-headers" }
 #include 
 
 // C++20 [futures.task.members]


[gcc r16-3933] libstdc++/ranges: Fix more wrong value type init from reference type [PR111861]

2025-09-17 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:3268c47c08782efe7fb1dd9a110bebe018e7d59c

commit r16-3933-g3268c47c08782efe7fb1dd9a110bebe018e7d59c
Author: Patrick Palka 
Date:   Wed Sep 17 14:14:37 2025 -0400

libstdc++/ranges: Fix more wrong value type init from reference type 
[PR111861]

As in r16-3912-g412a1f78b53709, this fixes some other spots where we
wrongly use a deduced type and non-direct-initialization when trying
to initialize a value type from an iterator's reference type.

PR libstdc++/111861

libstdc++-v3/ChangeLog:

* include/bits/ranges_algo.h (ranges::unique_copy): When
initializing a value type object from *iter, use
direct-initialization and don't use a deduced type.
(ranges::push_heap): Use direct-initialization when initializing
a value type object from ranges::iter_move.
(ranges::max): As in ranges::unique_copy.
* include/bits/ranges_util.h (ranges::min): Likewise.

Reviewed-by: Jonathan Wakely 

Diff:
---
 libstdc++-v3/include/bits/ranges_algo.h | 8 
 libstdc++-v3/include/bits/ranges_util.h | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libstdc++-v3/include/bits/ranges_algo.h 
b/libstdc++-v3/include/bits/ranges_algo.h
index 4025bba9f204..5c9fe627aee0 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1529,7 +1529,7 @@ namespace ranges
  }
else // indirectly_copyable_storable<_Iter, _Out>
  {
-   auto __value = *__first;
+   iter_value_t<_Iter> __value(*__first);
*__result = __value;
while (++__first != __last)
  {
@@ -2075,9 +2075,9 @@ namespace ranges
else
  {
auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
+   iter_value_t<_Iter> 
__value(ranges::iter_move(ranges::prev(__last)));
__detail::__push_heap(__first, (__last - __first) - 1,
- 0, ranges::iter_move(ranges::prev(__last)),
- __comp_proj);
+ 0, std::move(__value), __comp_proj);
return __last;
  }
   }
@@ -4219,7 +4219,7 @@ namespace ranges
auto __first = ranges::begin(__r);
auto __last = ranges::end(__r);
__glibcxx_assert(__first != __last);
-   auto __result = *__first;
+   range_value_t<_Range> __result(*__first);
while (++__first != __last)
  {
auto&& __tmp = *__first;
diff --git a/libstdc++-v3/include/bits/ranges_util.h 
b/libstdc++-v3/include/bits/ranges_util.h
index 84de258908ea..2aa8938edf25 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -761,7 +761,7 @@ namespace ranges
auto __first = ranges::begin(__r);
auto __last = ranges::end(__r);
__glibcxx_assert(__first != __last);
-   auto __result = *__first;
+   range_value_t<_Range> __result(*__first);
while (++__first != __last)
  {
auto&& __tmp = *__first;


[gcc r14-12049] libstdc++/testsuite: Unpoison 'u' on s390x in names.cc test

2025-10-01 Thread Patrick Palka via Libstdc++-cvs
https://gcc.gnu.org/g:c3a5b0290d529a75fc743da73dce34e095afde7c

commit r14-12049-gc3a5b0290d529a75fc743da73dce34e095afde7c
Author: Patrick Palka 
Date:   Tue Sep 23 22:41:26 2025 -0400

libstdc++/testsuite: Unpoison 'u' on s390x in names.cc test

This is the s390 counterpart to r11-7364-gd0453cf5c68b6a, and fixes the
following names.cc failure caused by a use of a poisoned identifier.
If we look at the corresponding upstream header[1] it's clear that the
problematic identifier is 'u'.

In file included from /usr/include/linux/types.h:5,
 from /usr/include/linux/sched/types.h:5,
 from /usr/include/bits/sched.h:61,
 from /usr/include/sched.h:43,
 from /usr/include/pthread.h:22,
 from 
/usr/include/c++/14/s390x-redhat-linux/bits/gthr-default.h:35,
 from 
/usr/include/c++/14/s390x-redhat-linux/bits/gthr.h:157,
 from /usr/include/c++/14/ext/atomicity.h:35,
 from /usr/include/c++/14/bits/ios_base.h:39,
 from /usr/include/c++/14/streambuf:43,
 from /usr/include/c++/14/bits/streambuf_iterator.h:35,
 from /usr/include/c++/14/iterator:66,
 from 
/usr/include/c++/14/s390x-redhat-linux/bits/stdc++.h:54,
 from 
/root/rpmbuild/BUILD/gcc-14.3.1-20250617/libstdc++-v3/testsuite/17_intro/names.cc:384:
/usr/include/asm/types.h:24: error: expected unqualified-id before '[' token
/usr/include/asm/types.h:24: error: expected ')' before '[' token

/root/rpmbuild/BUILD/gcc-14.3.1-20250617/libstdc++-v3/testsuite/17_intro/names.cc:101:
 note: to match this '('
compiler exited with status 1
FAIL: 17_intro/names.cc  -std=gnu++98 (test for excess errors)
Excess errors:
/usr/include/asm/types.h:24: error: expected unqualified-id before '[' token
/usr/include/asm/types.h:24: error: expected ')' before '[' token

[1]: 
https://github.com/torvalds/linux/blob/master/arch/s390/include/uapi/asm/types.h

libstdc++-v3/ChangeLog:

* testsuite/17_intro/names.cc: Undefine 'u' on s390*-linux.

Reviewed-by: Jonathan Wakely 
(cherry picked from commit e9f3138f38067664bae25947ebabc0e8fa223d43)

Diff:
---
 libstdc++-v3/testsuite/17_intro/names.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libstdc++-v3/testsuite/17_intro/names.cc 
b/libstdc++-v3/testsuite/17_intro/names.cc
index 5acbdf38044d..5b4ad97c724f 100644
--- a/libstdc++-v3/testsuite/17_intro/names.cc
+++ b/libstdc++-v3/testsuite/17_intro/names.cc
@@ -280,6 +280,8 @@
 //  defines fpreg_t::d and fpreg_t::f
 #undef d
 #undef f
+//  defines __vector128::u
+#undef u
 #endif
 
 #if defined (__linux__) && defined (__sparc__)