From a66163b194a75d1215ab02901eeebb5b3075eb2a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 20 Jun 2026 20:07:00 +0800 Subject: [PATCH 1/2] Implement LWG-4125 --- stl/inc/xutility | 17 ++++++++++-- tests/libcxx/expected_results.txt | 3 --- .../test.cpp | 27 ++++++++++++++++++- .../tests/P2441R2_views_join_with/test.cpp | 3 --- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 488bc52d044..27a39ca77be 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4393,7 +4393,11 @@ struct _Move_iterator_category { _EXPORT_STD template class move_iterator : public _Move_iterator_category<_Iter> { private: - _Iter _Current{}; +#if _HAS_CXX17 + _Iter _Current = _Iter(); +#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv + _Iter _Current; +#endif // ^^^ !_HAS_CXX17 ^^^ public: using iterator_type = _Iter; @@ -4424,7 +4428,16 @@ public: conditional_t>, remove_reference_t<_Iter_ref_t<_Iter>>&&, _Iter_ref_t<_Iter>>; #endif // ^^^ !_HAS_CXX20 ^^^ - _CONSTEXPR17 move_iterator() = default; +#if _HAS_CXX17 + constexpr move_iterator() +#if _HAS_CXX20 + requires default_initializable<_Iter> +#endif // _HAS_CXX20 + = default; +#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv + move_iterator() noexcept(is_nothrow_default_constructible_v<_Iter>) // strengthened + : _Current() {} +#endif // ^^^ !_HAS_CXX17 ^^^ _CONSTEXPR17 explicit move_iterator(_Iter _Right) noexcept(is_nothrow_move_constructible_v<_Iter>) // strengthened : _Current(_STD move(_Right)) {} diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 8f02805626c..25f119da8f0 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -861,9 +861,6 @@ std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp:2 FAIL std/input.output/filesystems/class.path/path.member/path.charconv.pass.cpp:0 FAIL std/input.output/filesystems/class.path/path.member/path.charconv.pass.cpp:1 FAIL -# Not analyzed. Clang is attempting to default construct cpp17_input_iterator. -std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp:2 FAIL - # Not analyzed. Asserting about alloc_count. std/thread/futures/futures.promise/alloc_ctor.pass.cpp FAIL std/thread/futures/futures.promise/move_assign.pass.cpp FAIL diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index 048d6d00dfb..8ebc8864eab 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -115,6 +115,20 @@ struct simple_input_iter { bool operator==(simple_input_iter const&) const = default; }; +struct empty_list_input_iter { + using value_type = double; + using difference_type = long; + + // not default constructible, although initializable with {} + explicit empty_list_input_iter(std::initializer_list); + + value_type operator*() const; + empty_list_input_iter& operator++(); + empty_list_input_iter operator++(int); + + bool operator==(const empty_list_input_iter&) const = default; +}; + template struct simple_forward_iter : Base { using value_type = double; @@ -943,6 +957,7 @@ namespace iterator_traits_test { // * 3.2.2: "... Otherwise, reference names iter_reference_t." // * 3.2.3.4 "... Otherwise, iterator_category names... input_iterator_tag." static_assert(check()); + static_assert(check()); // N4928 [iterator.traits]: // * 3.2.1: "... Otherwise, pointer names void." @@ -3330,7 +3345,7 @@ namespace reverse_iterator_test { namespace move_iterator_test { using std::bidirectional_iterator_tag, std::default_sentinel_t, std::forward_iterator_tag, std::input_iterator_tag, std::move_iterator, std::move_sentinel, std::random_access_iterator_tag, std::same_as, std::string, - std::three_way_comparable, std::three_way_comparable_with; + std::three_way_comparable, std::three_way_comparable_with, std::default_initializable; template struct input_iter { @@ -3419,6 +3434,8 @@ namespace move_iterator_test { static_assert(same_as>::iterator_category, forward_iterator_tag>); static_assert(same_as::iterator_concept, input_iterator_tag>); static_assert(same_as::iterator_category, input_iterator_tag>); + static_assert(same_as::iterator_concept, input_iterator_tag>); + static_assert(same_as::iterator_category, input_iterator_tag>); static_assert(same_as>::iterator_concept, input_iterator_tag>); static_assert(same_as::iterator_concept, random_access_iterator_tag>); static_assert(same_as::iterator_category, random_access_iterator_tag>); @@ -3524,6 +3541,14 @@ namespace move_iterator_test { static_assert(!three_way_comparable>, move_sentinel>); + // LWG-4125 "move_iterator's default constructor should be constrained" + // Validate default-constructibility + static_assert(!default_initializable>); + static_assert(!default_initializable>); + static_assert(default_initializable>>); + static_assert(default_initializable>>); + static_assert(default_initializable>); + // GH-3014 ": list-initialization is misused" void test_gh_3014() { // COMPILE-ONLY using S = test::init_list_not_constructible_sentinel; diff --git a/tests/std/tests/P2441R2_views_join_with/test.cpp b/tests/std/tests/P2441R2_views_join_with/test.cpp index 017c3e12aac..d8f3e9dcdc2 100644 --- a/tests/std/tests/P2441R2_views_join_with/test.cpp +++ b/tests/std/tests/P2441R2_views_join_with/test.cpp @@ -375,9 +375,6 @@ struct instantiator { Outer empty{span{}}; test_one(empty, "*#"sv, views::empty); } -#if defined(__clang__) || defined(__EDG__) // TRANSITION, LLVM-60293 and VSO-1900294 - if constexpr (ranges::forward_range || ranges::common_range) -#endif // ^^^ workaround ^^^ { // Range-of-rvalue delimiter Inner inner_ranges[] = {Inner{span{input[0]}}, Inner{span{input[1]}}, Inner{span{input[2]}}, Inner{span{input[3]}}, Inner{span{input[4]}}, Inner{span{input[5]}}, Inner{span{input[6]}}, From e7b2d43003e3df61f3775fe6347c96d2502adefa Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 23 Jun 2026 13:59:37 +0800 Subject: [PATCH 2/2] Unconditionally use `_Iter _Current = _Iter();` --- stl/inc/xutility | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 27a39ca77be..9805c923118 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4393,11 +4393,7 @@ struct _Move_iterator_category { _EXPORT_STD template class move_iterator : public _Move_iterator_category<_Iter> { private: -#if _HAS_CXX17 _Iter _Current = _Iter(); -#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv - _Iter _Current; -#endif // ^^^ !_HAS_CXX17 ^^^ public: using iterator_type = _Iter; @@ -4428,16 +4424,11 @@ public: conditional_t>, remove_reference_t<_Iter_ref_t<_Iter>>&&, _Iter_ref_t<_Iter>>; #endif // ^^^ !_HAS_CXX20 ^^^ -#if _HAS_CXX17 - constexpr move_iterator() + _CONSTEXPR17 move_iterator() #if _HAS_CXX20 requires default_initializable<_Iter> #endif // _HAS_CXX20 = default; -#else // ^^^ _HAS_CXX17 / !_HAS_CXX17 vvv - move_iterator() noexcept(is_nothrow_default_constructible_v<_Iter>) // strengthened - : _Current() {} -#endif // ^^^ !_HAS_CXX17 ^^^ _CONSTEXPR17 explicit move_iterator(_Iter _Right) noexcept(is_nothrow_move_constructible_v<_Iter>) // strengthened : _Current(_STD move(_Right)) {}