[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