[PATCH] libstdc++: Constrain views::adjacent(_transform)?<0> to forward_ranges.
Tomasz Kamiński
tkaminsk@redhat.com
Fri Apr 24 10:04:02 GMT 2026
This resolves LWG 4098, "views::adjacent<0> should reject non-forward ranges"
which was approved in Sofia 2024.
libstdc++-v3/ChangeLog:
* include/std/ranges (_AdjacentTransform::operator())
(_Adjacent::operator()): Require forward_range for N == 0.
* testsuite/std/ranges/adaptors/adjacent/1.cc: Test if input_ranges
are rejected.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: Likewise.
---
Testing on x86_64-linux. *adaptors/adjacent* test passed.
OK for trunk when all tests passes?
libstdc++-v3/include/std/ranges | 10 ++++++++--
.../testsuite/std/ranges/adaptors/adjacent/1.cc | 7 +++++++
.../std/ranges/adaptors/adjacent_transform/1.cc | 7 +++++++
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 9c7d639a154..ba4c9f60ab2 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -5859,8 +5859,11 @@ namespace views::__adaptor
template<size_t _Nm>
struct _Adjacent : __adaptor::_RangeAdaptorClosure<_Adjacent<_Nm>>
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4098. views::adjacent<0> should reject non-forward ranges
template<viewable_range _Range>
- requires (_Nm == 0) || __detail::__can_adjacent_view<_Nm, _Range>
+ requires (_Nm == 0) && forward_range<_Range>
+ || __detail::__can_adjacent_view<_Nm, _Range>
constexpr auto
operator() [[nodiscard]] (_Range&& __r) const
{
@@ -6197,8 +6200,11 @@ namespace views::__adaptor
template<size_t _Nm>
struct _AdjacentTransform : __adaptor::_RangeAdaptor<_AdjacentTransform<_Nm>>
{
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4098. views::adjacent<0> should reject non-forward ranges
template<viewable_range _Range, typename _Fp>
- requires (_Nm == 0) || __detail::__can_adjacent_transform_view<_Nm, _Range, _Fp>
+ requires (_Nm == 0) && forward_range<_Range>
+ || __detail::__can_adjacent_transform_view<_Nm, _Range, _Fp>
constexpr auto
operator() [[nodiscard]] (_Range&& __r, _Fp&& __f) const
{
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
index 0a5c67f5614..57322922e5e 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent/1.cc
@@ -9,6 +9,13 @@
namespace ranges = std::ranges;
namespace views = std::views;
+template<typename Range>
+concept can_adjacent0 = requires (Range& rg)
+{ views::adjacent<0>(rg); };
+
+static_assert( !can_adjacent0<__gnu_test::test_input_range<int>> );
+static_assert( can_adjacent0<__gnu_test::test_forward_range<int>> );
+
constexpr bool
test01()
{
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 6890618754b..a75d02efbb8 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
@@ -9,6 +9,13 @@
namespace ranges = std::ranges;
namespace views = std::views;
+template<typename Range>
+concept can_adjacent0 = requires (Range& rg)
+{ views::adjacent_transform<0>(rg, []() { return 10; }); };
+
+static_assert( !can_adjacent0<__gnu_test::test_input_range<int>> );
+static_assert( can_adjacent0<__gnu_test::test_forward_range<int>> );
+
constexpr bool
test01()
{
--
2.53.0
More information about the Libstdc++
mailing list