[gcc r15-3090] libstdc++: Implement P2997R1 changes to the indirect invocability concepts
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
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
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
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
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
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]
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]
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
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
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
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
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
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
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
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
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()
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]
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|
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
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]
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]
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
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
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)
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)
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]
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
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
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]
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]
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]
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]
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]
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]
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]
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]
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
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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==
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==
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
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
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
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]
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()
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]
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
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
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
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
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]
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
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__)