diff --git a/stl/inc/iterator b/stl/inc/iterator index 6af048c0988..5eeb541f246 100644 --- a/stl/inc/iterator +++ b/stl/inc/iterator @@ -187,13 +187,13 @@ public: constexpr move_sentinel() = default; constexpr explicit move_sentinel(_Se _Val) noexcept(is_nothrow_move_constructible_v<_Se>) // strengthened - : _Last{_STD move(_Val)} {} + : _Last(_STD move(_Val)) {} template requires convertible_to constexpr move_sentinel(const move_sentinel<_Se2>& _Val) noexcept( is_nothrow_constructible_v<_Se, const _Se2&>) // strengthened - : _Last{_Val._Get_last()} {} + : _Last(_Val._Get_last()) {} template requires assignable_from<_Se&, const _Se2&> diff --git a/stl/inc/ranges b/stl/inc/ranges index 78b1c04e432..ff0bdda974a 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -2380,12 +2380,10 @@ namespace ranges { #endif // _ITERATOR_DEBUG_LEVEL != 0 } - // clang-format off - constexpr _Iterator(_Iterator _It) - noexcept(is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened + constexpr _Iterator(_Iterator _It) noexcept( + is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened requires _Const && convertible_to, iterator_t<_Base>> - : _Current{_STD move(_It._Current)}, _Parent{_It._Parent} {} - // clang-format on + : _Current(_STD move(_It._Current)), _Parent(_It._Parent) {} _NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept { return _Current; @@ -3694,7 +3692,7 @@ namespace ranges { constexpr _Iterator(_Iterator _It) requires _Const && convertible_to, _OuterIter> && convertible_to>, _InnerIter> - : _Outer{_STD move(_It._Outer)}, _Inner{_STD move(_It._Inner)}, _Parent{_It._Parent} {} + : _Outer(_STD move(_It._Outer)), _Inner(_STD move(_It._Inner)), _Parent(_It._Parent) {} _NODISCARD constexpr decltype(auto) operator*() const noexcept(noexcept(**_Inner)) /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 @@ -4020,7 +4018,7 @@ namespace ranges { _Variantish<_PatternIter, _InnerIter> _Inner_it{}; constexpr _Iterator(_Parent_t& _Parent_, iterator_t<_Base> _Outer_) - : _Parent{_STD addressof(_Parent_)}, _Outer_it{_STD move(_Outer_)} { + : _Parent(_STD addressof(_Parent_)), _Outer_it(_STD move(_Outer_)) { if (_Outer_it != _RANGES end(_Parent->_Range)) { auto&& _Inner = _Update_inner(); _Inner_it._Emplace_second(_RANGES begin(_Inner)); @@ -4104,7 +4102,7 @@ namespace ranges { && convertible_to, _OuterIter> // && convertible_to>, _InnerIter> // && convertible_to, _PatternIter> // - : _Outer_it{_STD move(_It._Outer_it)}, _Parent{_It._Parent} { + : _Parent(_It._Parent), _Outer_it(_STD move(_It._Outer_it)) { switch (_It._Inner_it._Contains) { case _Variantish_state::_Holds_first: _Inner_it._Emplace_first(_STD move(_It._Inner_it._First)); @@ -4294,7 +4292,7 @@ namespace ranges { constexpr _Sentinel(_Sentinel _Se) noexcept( is_nothrow_constructible_v, sentinel_t<_Vw>>) // strengthened requires _Const && convertible_to, sentinel_t<_Base>> - : _Last{_STD move(_Se._Last)} {} + : _Last(_STD move(_Se._Last)) {} template requires sentinel_for, iterator_t<_Maybe_const<_OtherConst, _Vw>>> @@ -5541,7 +5539,7 @@ namespace ranges { constexpr _Iterator(_Iterator _It) noexcept( is_nothrow_constructible_v, iterator_t<_Vw>>) // strengthened requires _Const && convertible_to, iterator_t<_Base>> - : _Current{_STD move(_It._Current)} {} + : _Current(_STD move(_It._Current)) {} _NODISCARD constexpr const iterator_t<_Base>& base() const& noexcept { return _Current; diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 36597c5160c..e6b629025b2 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -383,6 +383,37 @@ struct std::basic_common_reference<::test::proxy_reference, ::test: }; namespace test { + template + struct init_list_not_constructible_sentinel { + init_list_not_constructible_sentinel() = default; + init_list_not_constructible_sentinel(T*) {} + + template + init_list_not_constructible_sentinel(std::initializer_list) = delete; + }; + + template + struct init_list_not_constructible_iterator { + using difference_type = int; + using value_type = T; + + init_list_not_constructible_iterator() = default; + init_list_not_constructible_iterator(T*) {} + + template + init_list_not_constructible_iterator(std::initializer_list) = delete; + + T& operator*() const; // not defined + init_list_not_constructible_iterator& operator++(); // not defined + init_list_not_constructible_iterator operator++(int); // not defined + + bool operator==(init_list_not_constructible_sentinel) const; // not defined + }; + + static_assert(std::input_iterator>); + static_assert( + std::sentinel_for, init_list_not_constructible_iterator>); + template }, diff --git a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp index 09e34c98304..4335bf5cc40 100644 --- a/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp +++ b/tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp @@ -11,12 +11,7 @@ #include #include -#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) - -namespace ranges = std::ranges; - -template -inline constexpr bool always_false = false; +#include template using reference_to = T&; @@ -3448,6 +3443,16 @@ namespace move_iterator_test { STATIC_ASSERT(!three_way_comparable>, move_sentinel>); + // GH-3014 ": list-initialization is misused" + void test_gh_3014() { // COMPILE-ONLY + using S = test::init_list_not_constructible_sentinel; + S s; + [[maybe_unused]] move_sentinel y{s}; // Check 'move_sentinel(S s)' + + move_sentinel s2; + [[maybe_unused]] move_sentinel z{s2}; // Check 'move_sentinel(const move_sentinel& s2)' + } + constexpr bool test() { // Validate iter_move int count = 0; diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index f19e4a09adc..1bff24a240a 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -394,6 +394,26 @@ constexpr void instantiation_test() { #endif // TEST_EVERYTHING } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + P* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator

begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::elements<0>; + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { { // Validate copyable views constexpr span s{some_pairs}; diff --git a/tests/std/tests/P0896R4_views_join/test.cpp b/tests/std/tests/P0896R4_views_join/test.cpp index 7da95ce34bc..919ce6afa2f 100644 --- a/tests/std/tests/P0896R4_views_join/test.cpp +++ b/tests/std/tests/P0896R4_views_join/test.cpp @@ -503,6 +503,26 @@ void test_non_trivially_destructible_type() { // COMPILE-ONLY auto r2 = views::empty | views::transform([](Inner& r) { return r; }) | views::join; } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + string* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::join; + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { // Validate views constexpr string_view expected = "Hello World!"sv; diff --git a/tests/std/tests/P0896R4_views_transform/test.cpp b/tests/std/tests/P0896R4_views_transform/test.cpp index 887884c942d..e314e7e6a33 100644 --- a/tests/std/tests/P0896R4_views_transform/test.cpp +++ b/tests/std/tests/P0896R4_views_transform/test.cpp @@ -811,6 +811,26 @@ void test_gh_1709() { } } +// GH-3014 ": list-initialization is misused" +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + int* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator begin() const { + return nullptr; + } + + unreachable_sentinel_t end() const { + return {}; + } + }; + + auto r = InRange{} | views::transform(identity{}); + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' +} + int main() { { // Validate copyable views constexpr span s{some_ints}; diff --git a/tests/std/tests/P2441R2_views_join_with/test.cpp b/tests/std/tests/P2441R2_views_join_with/test.cpp index d5b965a47cc..852d78745ce 100644 --- a/tests/std/tests/P2441R2_views_join_with/test.cpp +++ b/tests/std/tests/P2441R2_views_join_with/test.cpp @@ -558,6 +558,41 @@ void test_valueless_iterator() { } } +// GH-3014 ": list-initialization is misused" +struct FakeStr { + const char* begin() { + return nullptr; + } + + unreachable_sentinel_t end() { + return {}; + } +}; + +void test_gh_3014() { // COMPILE-ONLY + struct InRange { + FakeStr* begin() { + return nullptr; + } + + test::init_list_not_constructible_iterator begin() const { + return nullptr; + } + + FakeStr* end() { + return nullptr; + } + + test::init_list_not_constructible_sentinel end() const { + return nullptr; + } + }; + + auto r = InRange{} | views::join_with('-'); + [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' + [[maybe_unused]] decltype(as_const(r).end()) s = r.end(); // Check 'sentinel(sentinel s)' +} + int main() { { auto filtered_and_joined =