[libcxx-commits] [libcxx] [libc++] Implement LWG4125: `move_iterator`'s default constructor should be constrained (PR #206427)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jun 29 03:36:46 PDT 2026
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/206427
>From 360994be788fcd7b7ab4ac5a601ba3d065d5d863 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 29 Jun 2026 16:22:25 +0800
Subject: [PATCH 1/3] [libc++] LWG4125: `move_iterator`'s default constructor
should be constrained
- The default constructor is not yet defaulted as indicated by the
resolution of LWG4125, because the effects of defaulted-ness is not
strictly observable. Also, it's arguable not feasible to use default
member initializer `= _Iter()` because it might cause non-conforming
behavior in pre-C++17 modes, due to lack of guaranteed RVO.
- In the test file, `NoDefaultCtr` is replaced with a proper iterator
type `cpp20_input_iterator<int*>` to make the test more pedantically
conforming.
---
libcxx/docs/Status/Cxx29Issues.csv | 2 +-
libcxx/include/__iterator/move_iterator.h | 4 +-
.../move.iter.op.const/default.pass.cpp | 37 ++++++++++++++-----
3 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/libcxx/docs/Status/Cxx29Issues.csv b/libcxx/docs/Status/Cxx29Issues.csv
index d9e245a9a11c0..13056a97782df 100644
--- a/libcxx/docs/Status/Cxx29Issues.csv
+++ b/libcxx/docs/Status/Cxx29Issues.csv
@@ -1,7 +1,7 @@
"Issue #","Issue Name","Meeting","Status","First released version","GitHub issue","Notes"
"`LWG3417 <https://wg21.link/LWG3417>`__","Missing ``volatile`` atomic deprecations","2026-06 (Brno)","","","`#204440 <https://github.com/llvm/llvm-project/issues/204440>`__",""
"`LWG4121 <https://wg21.link/LWG4121>`__","``ranges::to`` constructs associative containers via ``c.emplace(c.end(), *it)``","2026-06 (Brno)","","","`#204441 <https://github.com/llvm/llvm-project/issues/204441>`__",""
-"`LWG4125 <https://wg21.link/LWG4125>`__","``move_iterator``'s default constructor should be constrained","2026-06 (Brno)","","","`#204442 <https://github.com/llvm/llvm-project/issues/204442>`__",""
+"`LWG4125 <https://wg21.link/LWG4125>`__","``move_iterator``'s default constructor should be constrained","2026-06 (Brno)","|Complete|","23","`#204442 <https://github.com/llvm/llvm-project/issues/204442>`__",""
"`LWG4158 <https://wg21.link/LWG4158>`__","``packaged_task::operator=`` should abandon its shared state","2026-06 (Brno)","","","`#204443 <https://github.com/llvm/llvm-project/issues/204443>`__",""
"`LWG4182 <https://wg21.link/LWG4182>`__","Definition of ``NULL`` is too broad","2026-06 (Brno)","","","`#204444 <https://github.com/llvm/llvm-project/issues/204444>`__",""
"`LWG4218 <https://wg21.link/LWG4218>`__","Constraint recursion in ``basic_const_iterator``'s relational operators due to ADL + CWG 2369","2026-06 (Brno)","","","`#204445 <https://github.com/llvm/llvm-project/issues/204445>`__",""
diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h
index c42f4cb53e9a8..aa5570c018737 100644
--- a/libcxx/include/__iterator/move_iterator.h
+++ b/libcxx/include/__iterator/move_iterator.h
@@ -13,6 +13,7 @@
#include <__compare/compare_three_way_result.h>
#include <__compare/three_way_comparable.h>
#include <__concepts/assignable.h>
+#include <__concepts/constructible.h>
#include <__concepts/convertible_to.h>
#include <__concepts/derived_from.h>
#include <__concepts/same_as.h>
@@ -27,7 +28,6 @@
#include <__type_traits/conditional.h>
#include <__type_traits/enable_if.h>
#include <__type_traits/is_assignable.h>
-#include <__type_traits/is_constructible.h>
#include <__type_traits/is_convertible.h>
#include <__type_traits/is_reference.h>
#include <__type_traits/is_same.h>
@@ -122,7 +122,7 @@ class move_iterator
#if _LIBCPP_STD_VER >= 20
_LIBCPP_HIDE_FROM_ABI constexpr move_iterator()
- requires is_constructible_v<_Iter>
+ requires default_initializable<_Iter>
: __current_() {}
template <class _Up>
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
index d095182c560d8..00512fa2f3dad 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
@@ -10,11 +10,8 @@
// move_iterator
-// move_iterator();
-//
-// constexpr in C++17
-//
-// requires the underlying iterator to be default-constructible (extension).
+// constexpr move_iterator(); // constexpr since C++17
+// requires default_initializable<Iterator>; // since C++20
#include <iterator>
@@ -22,13 +19,33 @@
#include "test_macros.h"
#include "test_iterators.h"
-#if TEST_STD_VER > 17
-struct NoDefaultCtr : forward_iterator<int*> {
- NoDefaultCtr() = delete;
+#if TEST_STD_VER >= 20
+class constable_iter {
+public:
+ using iterator_category = std::input_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = char;
+
+ constable_iter() = default;
+
+ template <class U = constable_iter>
+ const constable_iter& operator=(const std::type_identity_t<constable_iter>&) const;
+
+ char operator*() const;
+
+ const constable_iter& operator++() const;
+ void operator++(int) const;
+
+private:
+ char payload_; // making `const constable_iter` value-initializable but not default-initializable
};
+static_assert(std::is_default_constructible_v<const constable_iter>);
+static_assert(!std::default_initializable<const constable_iter>);
+static_assert(std::input_iterator<const constable_iter>);
-LIBCPP_STATIC_ASSERT( std::is_default_constructible_v<std::move_iterator<forward_iterator<int*>>>);
-LIBCPP_STATIC_ASSERT(!std::is_default_constructible_v<std::move_iterator<NoDefaultCtr>>);
+static_assert(std::is_default_constructible_v<std::move_iterator<forward_iterator<int*>>>);
+static_assert(!std::is_default_constructible_v<std::move_iterator<cpp20_input_iterator<int*>>>);
+static_assert(!std::is_default_constructible_v<std::move_iterator<const constable_iter>>);
#endif
template <class It>
>From 5506f5472ea4d26a300472d2556e883807e9638c Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 29 Jun 2026 16:58:23 +0800
Subject: [PATCH 2/3] Fix-up test
---
.../move.iter.ops/move.iter.op.const/default.pass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
index 00512fa2f3dad..6ef2e4b3652ee 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
@@ -23,7 +23,7 @@
class constable_iter {
public:
using iterator_category = std::input_iterator_tag;
- using difference_type = std::ptrdiff_t;
+ using difference_type = int;
using value_type = char;
constable_iter() = default;
>From 9bec60c1b0d282bc340bf40de0f641e636d9dac3 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 29 Jun 2026 18:36:20 +0800
Subject: [PATCH 3/3] Fixup test: Get rid of complicated trick.
---
.../move.iter.ops/move.iter.op.const/default.pass.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
index 6ef2e4b3652ee..2574138bbef9a 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
@@ -28,8 +28,8 @@ class constable_iter {
constable_iter() = default;
- template <class U = constable_iter>
- const constable_iter& operator=(const std::type_identity_t<constable_iter>&) const;
+ template <class = void>
+ const constable_iter& operator=(const constable_iter&) const;
char operator*() const;
More information about the libcxx-commits
mailing list