[libcxx-commits] [libcxx] [libc++] Implement LWG3601: `common_iterator`'s postfix-proxy needs `indirectly_readable` (PR #237574)
R. Aoto via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Oct 31 08:11:32 PDT 2026
https://github.com/aotodev created https://github.com/llvm/llvm-project/pull/237574
`common_iterator::operator++(int)` now returns the postfix-proxy only when the underlying iterator is `indirectly_readable`. Previously, a non-readable iterator with a usable `value_type` and a non-referenceable `*it++` got a proxy holding a copied value. Now it gets the result of the underlying `it++`.
Fixes #104946
>From b234b61f6de5527830fea98ef1ec5c25a2a5701a Mon Sep 17 00:00:00 2001
From: Aoto <aotodev at gmail.com>
Date: Sat, 31 Oct 2026 15:58:29 +0100
Subject: [PATCH] [libc++] Implement LWG3601: `common_iterator`'s postfix-proxy
needs `indirectly_readable`
---
libcxx/docs/Status/Cxx23Issues.csv | 2 +-
libcxx/include/__iterator/common_iterator.h | 3 ++-
.../iterators.common/plus_plus.pass.cpp | 17 ++++++++++++++
.../predef.iterators/iterators.common/types.h | 22 +++++++++++++++++++
4 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv
index b6f118f03e0fd9..369fbecde82fa2 100644
--- a/libcxx/docs/Status/Cxx23Issues.csv
+++ b/libcxx/docs/Status/Cxx23Issues.csv
@@ -141,7 +141,7 @@
"`LWG3471 <https://wg21.link/LWG3471>`__","``polymorphic_allocator::allocate`` does not satisfy ``Cpp17Allocator`` requirements","2022-02 (Virtual)","","","`#104943 <https://github.com/llvm/llvm-project/issues/104943>`__",""
"`LWG3525 <https://wg21.link/LWG3525>`__","``uses_allocator_construction_args`` fails to handle types convertible to ``pair``","2022-02 (Virtual)","","","`#104944 <https://github.com/llvm/llvm-project/issues/104944>`__",""
"`LWG3598 <https://wg21.link/LWG3598>`__","``system_category().default_error_condition(0)`` is underspecified","2022-02 (Virtual)","","","`#104945 <https://github.com/llvm/llvm-project/issues/104945>`__",""
-"`LWG3601 <https://wg21.link/LWG3601>`__","common_iterator's postfix-proxy needs ``indirectly_readable`` ","2022-02 (Virtual)","","","`#104946 <https://github.com/llvm/llvm-project/issues/104946>`__",""
+"`LWG3601 <https://wg21.link/LWG3601>`__","common_iterator's postfix-proxy needs ``indirectly_readable`` ","2022-02 (Virtual)","|Complete|","24","`#104946 <https://github.com/llvm/llvm-project/issues/104946>`__",""
"`LWG3607 <https://wg21.link/LWG3607>`__","``contiguous_iterator`` should not be allowed to have custom ``iter_move`` and ``iter_swap`` behavior","2022-02 (Virtual)","|Nothing To Do|","","`#104947 <https://github.com/llvm/llvm-project/issues/104947>`__",""
"`LWG3610 <https://wg21.link/LWG3610>`__","``iota_view::size`` sometimes rejects integer-class types","2022-02 (Virtual)","|Complete|","23","`#104948 <https://github.com/llvm/llvm-project/issues/104948>`__",""
"`LWG3612 <https://wg21.link/LWG3612>`__","Inconsistent pointer alignment in ``std::format`` ","2022-02 (Virtual)","|Complete|","14","`#104949 <https://github.com/llvm/llvm-project/issues/104949>`__",""
diff --git a/libcxx/include/__iterator/common_iterator.h b/libcxx/include/__iterator/common_iterator.h
index 02d4cac0e669aa..30fbe1b6dd2338 100644
--- a/libcxx/include/__iterator/common_iterator.h
+++ b/libcxx/include/__iterator/common_iterator.h
@@ -46,7 +46,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template <class _Iter>
concept __can_use_postfix_proxy =
- constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>> && move_constructible<iter_value_t<_Iter>>;
+ indirectly_readable<_Iter> && constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>> &&
+ move_constructible<iter_value_t<_Iter>>;
template <input_or_output_iterator _Iter, sentinel_for<_Iter> _Sent>
requires(!same_as<_Iter, _Sent> && copyable<_Iter>)
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
index dad7ff5081a1f1..b2b340d73f19e1 100644
--- a/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
@@ -95,6 +95,23 @@ void test() {
assert(commonIter1 == commonSent1);
}
+ // Case 2: not indirectly_readable (LWG3601)
+ {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ using Iter = non_const_deref_iterator<int*>;
+ using Common = std::common_iterator<Iter, sentinel_type<int*>>;
+ auto iter = Common(Iter(buffer));
+ auto sent = Common(sentinel_type<int*>{buffer + 8});
+
+ static_assert(!std::indirectly_readable<Iter>);
+ ASSERT_SAME_TYPE(decltype(iter++), void);
+
+ for (int i = 1; iter != sent; ++i) {
+ assert(*iter == i);
+ iter++;
+ }
+ }
+
// Case 2: can-reference
{
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
index f5717f3eb3df37..28283d5aa7735b 100644
--- a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
@@ -121,6 +121,28 @@ class value_type_not_move_constructible_iterator
constexpr void operator++(int) {++(*this);}
};
+// Not indirectly_readable: operator* is non-const. Postfix ++ returns void, so *it++ is ill-formed.
+template <class It>
+class non_const_deref_iterator {
+ It it_;
+
+public:
+ using value_type = std::iter_value_t<It>;
+ using difference_type = std::iter_difference_t<It>;
+
+ friend constexpr It base(const non_const_deref_iterator& i) { return i.it_; }
+
+ explicit constexpr non_const_deref_iterator(It it) : it_(it) {}
+
+ constexpr decltype(auto) operator*() { return *it_; }
+
+ constexpr non_const_deref_iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+ constexpr void operator++(int) { ++it_; }
+};
+
template <class It>
class comparable_iterator
{
More information about the libcxx-commits
mailing list