diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -126,7 +126,7 @@ `3571 `__,"``flush_emit`` should set ``badbit`` if the ``emit`` call fails","October 2021","","" `3572 `__,"``copyable-box`` should be fully ``constexpr``","October 2021","","","|ranges|" `3573 `__,"Missing Throws element for ``basic_string_view(It begin, End end)``","October 2021","|Complete|","14.0" -`3574 `__,"``common_iterator`` should be completely ``constexpr``-able","October 2021","","","|ranges|" +`3574 `__,"``common_iterator`` should be completely ``constexpr``-able","October 2021","|Complete|","14.0","|ranges|" `3580 `__,"``iota_view``'s ``iterator``'s binary ``operator+`` should be improved","October 2021","","","|ranges|" `3581 `__,"The range constructor makes ``basic_string_view`` not trivially move constructible","October 2021","","","|ranges|" `3585 `__,"``variant`` converting assignment with immovable alternative","October 2021","","" @@ -135,7 +135,7 @@ `3591 `__,"``lazy_split_view::inner-iterator::base() &&`` invalidates outer iterators","October 2021","","","|ranges|" `3592 `__,"``lazy_split_view`` needs to check the simpleness of Pattern","October 2021","","","|ranges|" `3593 `__,"Several iterators' ``base() const &`` and ``lazy_split_view::outer-iterator::value_type::end()`` missing ``noexcept``","October 2021","","","|ranges|" -`3595 `__,"Exposition-only classes proxy and postfix-proxy for ``common_iterator`` should be fully ``constexpr``","October 2021","","","|ranges|" +`3595 `__,"Exposition-only classes proxy and postfix-proxy for ``common_iterator`` should be fully ``constexpr``","October 2021","|Complete|","14.0","|ranges|" "","","","","" `3645 `__,"``resize_and_overwrite`` is overspecified to call its callback with lvalues", "Not voted in","|Complete|","14.0","" "","","","","" diff --git a/libcxx/include/__iterator/common_iterator.h b/libcxx/include/__iterator/common_iterator.h --- a/libcxx/include/__iterator/common_iterator.h +++ b/libcxx/include/__iterator/common_iterator.h @@ -41,7 +41,7 @@ : __value(_VSTD::move(__x)) {} public: - const iter_value_t<_Iter>* operator->() const { + constexpr const iter_value_t<_Iter>* operator->() const noexcept { return _VSTD::addressof(__value); } }; @@ -58,7 +58,7 @@ constructible_from, iter_reference_t<_Iter>> && move_constructible>; - const iter_value_t<_Iter>& operator*() const { + constexpr const iter_value_t<_Iter>& operator*() const noexcept { return __value; } }; @@ -75,7 +75,7 @@ requires convertible_to && convertible_to constexpr common_iterator(const common_iterator<_I2, _S2>& __other) : __hold_([&]() -> variant<_Iter, _Sent> { - _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Constructed from valueless iterator."); + _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Attempted to construct from a valueless common_iterator"); if (__other.__hold_.index() == 0) return variant<_Iter, _Sent>{in_place_index<0>, _VSTD::__unchecked_get<0>(__other.__hold_)}; return variant<_Iter, _Sent>{in_place_index<1>, _VSTD::__unchecked_get<1>(__other.__hold_)}; @@ -85,7 +85,7 @@ requires convertible_to && convertible_to && assignable_from<_Iter&, const _I2&> && assignable_from<_Sent&, const _S2&> common_iterator& operator=(const common_iterator<_I2, _S2>& __other) { - _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Assigned from valueless iterator."); + _LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Attempted to assign from a valueless common_iterator"); auto __idx = __hold_.index(); auto __other_idx = __other.__hold_.index(); @@ -105,18 +105,16 @@ return *this; } - decltype(auto) operator*() + constexpr decltype(auto) operator*() { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); return *_VSTD::__unchecked_get<_Iter>(__hold_); } - decltype(auto) operator*() const + constexpr decltype(auto) operator*() const requires __dereferenceable { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); return *_VSTD::__unchecked_get<_Iter>(__hold_); } @@ -127,9 +125,7 @@ is_reference_v> || constructible_from, iter_reference_t<_I2>>) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot dereference sentinel. Common iterator not holding an iterator."); - + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to dereference a non-dereferenceable common_iterator"); if constexpr (is_pointer_v<_Iter> || requires(const _Iter& __i) { __i.operator->(); }) { return _VSTD::__unchecked_get<_Iter>(__hold_); } else if constexpr (is_reference_v>) { @@ -141,15 +137,12 @@ } common_iterator& operator++() { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot increment sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); ++_VSTD::__unchecked_get<_Iter>(__hold_); return *this; } decltype(auto) operator++(int) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), - "Cannot increment sentinel. Common iterator not holding an iterator."); - + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), "Attempted to increment a non-dereferenceable common_iterator"); if constexpr (forward_iterator<_Iter>) { auto __tmp = *this; ++*this; @@ -166,10 +159,9 @@ template _S2> requires sentinel_for<_Sent, _I2> - friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot compare valueless iterators.)"); + friend constexpr bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -185,10 +177,9 @@ template _S2> requires sentinel_for<_Sent, _I2> && equality_comparable_with<_Iter, _I2> - friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot compare valueless iterators.)"); + friend constexpr bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to compare a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -207,10 +198,9 @@ template _I2, sized_sentinel_for<_Iter> _S2> requires sized_sentinel_for<_Sent, _I2> - friend iter_difference_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { - _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() && - !__y.__hold_.valueless_by_exception(), - "One or both common_iterators are valueless. (Cannot subtract valueless iterators.)"); + friend constexpr iter_difference_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) { + _LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception(), "Attempted to subtract from a valueless common_iterator"); + _LIBCPP_ASSERT(!__y.__hold_.valueless_by_exception(), "Attempted to subtract a valueless common_iterator"); auto __x_index = __x.__hold_.index(); auto __y_index = __y.__hold_.index(); @@ -227,24 +217,21 @@ return _VSTD::__unchecked_get<_Sent>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_); } - friend iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i) + friend constexpr iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i) noexcept(noexcept(ranges::iter_move(declval()))) requires input_iterator<_Iter> { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_), - "Cannot iter_move a sentinel. Common iterator not holding an iterator."); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_), "Attempted to iter_move a non-dereferenceable common_iterator"); return ranges::iter_move( _VSTD::__unchecked_get<_Iter>(__i.__hold_)); } template _I2, class _S2> - friend void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) + friend constexpr void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) noexcept(noexcept(ranges::iter_swap(declval(), declval()))) { - _LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_), - "Cannot swap __y with a sentinel. Common iterator (__x) not holding an iterator."); - _LIBCPP_ASSERT(holds_alternative<_Iter>(__y.__hold_), - "Cannot swap __x with a sentinel. Common iterator (__y) not holding an iterator."); - return ranges::iter_swap( _VSTD::__unchecked_get<_Iter>(__x.__hold_), _VSTD::__unchecked_get<_Iter>(__y.__hold_)); + _LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + _LIBCPP_ASSERT(holds_alternative<_I2>(__y.__hold_), "Attempted to iter_swap a non-dereferenceable common_iterator"); + return ranges::iter_swap(_VSTD::__unchecked_get<_Iter>(__x.__hold_), _VSTD::__unchecked_get<_I2>(__y.__hold_)); } }; @@ -271,7 +258,7 @@ template requires __common_iter_has_ptr_op<_Iter, _Sent> struct __arrow_type_or_void<_Iter, _Sent> { - using type = decltype(declval>().operator->()); + using type = decltype(declval&>().operator->()); }; template diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/constraints.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/constraints.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/constraints.compile.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template S> +// requires (!same_as && copyable) + +#include + +#include "test_iterators.h" + +template +concept ValidCommonIterator = requires { + typename std::common_iterator; +}; + +static_assert( ValidCommonIterator); +static_assert(!ValidCommonIterator); // !input_or_output_iterator +static_assert(!ValidCommonIterator); // !sentinel_for +static_assert(!ValidCommonIterator); // !same_as +static_assert(!ValidCommonIterator, sentinel_wrapper>>); // !copyable diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.converting.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.converting.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.converting.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// template +// requires convertible_to && convertible_to +// constexpr common_iterator(const common_iterator& x); + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + struct Base {}; + struct Derived : Base {}; + + using BaseIt = std::common_iterator; + using DerivedIt = std::common_iterator; + static_assert(std::is_convertible_v); // Derived* to Base* + static_assert(!std::is_constructible_v); // Base* to Derived* + + Derived a[10] = {}; + DerivedIt it = DerivedIt(a); // the iterator type + BaseIt jt = BaseIt(it); + assert(jt == BaseIt(a)); + + it = DerivedIt((const Derived*)a); // the sentinel type + jt = BaseIt(it); + assert(jt == BaseIt(a)); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.default.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// constexpr common_iterator() requires default_initializable = default; + +#include +#include + +#include "test_iterators.h" + +constexpr bool test() +{ + { + using It = cpp17_input_iterator; + using CommonIt = std::common_iterator>; + static_assert(!std::is_default_constructible_v); // premise + static_assert(!std::is_default_constructible_v); // conclusion + } + { + // The base iterator is value-initialized. + std::common_iterator> c; + assert(c == nullptr); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.iter.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.iter.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.iter.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// constexpr common_iterator(I i); + +#include +#include + +#include "test_iterators.h" + +template +constexpr bool test() { + using CommonIt = std::common_iterator>; + int a[] = {1,2,3}; + It it = It(a); + CommonIt lv = CommonIt(it); + assert(&*lv == a); + CommonIt rv = CommonIt(std::move(it)); + assert(&*rv == a); + + return true; +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + test(); + + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp +++ /dev/null @@ -1,90 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-no-concepts - -// constexpr common_iterator() requires default_initializable = default; -// constexpr common_iterator(I i); -// constexpr common_iterator(S s); -// template -// requires convertible_to && convertible_to -// constexpr common_iterator(const common_iterator& x); - -#include -#include - -#include "test_macros.h" -#include "types.h" - -template -concept ValidCommonIterator = requires { - typename std::common_iterator; -}; - -template -concept ConvCtorEnabled = requires(std::common_iterator> ci) { - std::common_iterator>(ci); -}; - -void test() { - int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - - static_assert( std::is_default_constructible_v>>); - static_assert(!std::is_default_constructible_v, sentinel_type>>); - - // Not copyable: - static_assert(!ValidCommonIterator, sentinel_type>); - // Same iter and sent: - static_assert(!ValidCommonIterator, cpp17_input_iterator>); - - { - auto iter1 = cpp17_input_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); - - assert(*iter1 == 1); - assert(*commonIter1 == 1); - assert(commonIter1 != commonSent1); - } - { - auto iter1 = forward_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); - - assert(*iter1 == 1); - assert(*commonIter1 == 1); - assert(commonIter1 != commonSent1); - } - { - auto iter1 = random_access_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); - - assert(*iter1 == 1); - assert(*commonIter1 == 1); - assert(commonIter1 != commonSent1); - } - - // Conversion constructor: - { - convertible_iterator conv{buffer}; - auto commonIter1 = std::common_iterator, sentinel_type>(conv); - auto commonIter2 = std::common_iterator, sentinel_type>(commonIter1); - assert(*commonIter2 == 1); - - static_assert( ConvCtorEnabled, convertible_iterator>); - static_assert(!ConvCtorEnabled, random_access_iterator>); - } -} - -int main(int, char**) { - test(); - - return 0; -} diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.sentinel.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.sentinel.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.sentinel.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts + +// constexpr common_iterator(S s); + +#include +#include +#include + +#include "test_iterators.h" + +template +constexpr bool test() { + using Sent = sentinel_wrapper; + using CommonIt = std::common_iterator; + int a[] = {1,2,3}; + It it = It(a); + Sent sent = Sent(It(a+1)); + + CommonIt lv = CommonIt(sent); + assert(lv == CommonIt(sent)); + assert(lv != CommonIt(it)); + if (!std::is_constant_evaluated()) { + assert(lv == std::next(CommonIt(it))); + } + + CommonIt rv = CommonIt(std::move(sent)); + assert(rv == CommonIt(sent)); + assert(rv != CommonIt(it)); + if (!std::is_constant_evaluated()) { + assert(rv == std::next(CommonIt(it))); + } + + return true; +} + +int main(int, char**) { + test>(); + test>(); + test>(); + test>(); + test>(); + test(); + test(); + + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp @@ -15,35 +15,79 @@ #include #include +#include +#include "test_iterators.h" #include "test_macros.h" -#include "types.h" -void test() { - int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; +struct IterMovingIt { + using value_type = int; + using difference_type = int; + explicit IterMovingIt() = default; + IterMovingIt(const IterMovingIt&); // copyable, but this test shouldn't make copies + IterMovingIt(IterMovingIt&&) = default; + IterMovingIt& operator=(const IterMovingIt&); + int& operator*() const; + constexpr IterMovingIt& operator++() { return *this; } + IterMovingIt operator++(int); + friend constexpr int iter_move(const IterMovingIt&) { + return 42; + } + bool operator==(std::default_sentinel_t) const; +}; +static_assert(std::input_iterator); +constexpr bool test() { { - auto iter1 = cpp17_input_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - assert(std::ranges::iter_move(commonIter1) == 1); - ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&); + using It = int*; + using CommonIt = std::common_iterator>; + int a[] = {1, 2, 3}; + CommonIt it = CommonIt(It(a)); + ASSERT_NOEXCEPT(iter_move(it)); + ASSERT_NOEXCEPT(std::ranges::iter_move(it)); + ASSERT_SAME_TYPE(decltype(iter_move(it)), int&&); + ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(it)), int&&); + assert(iter_move(it) == 1); + if (!std::is_constant_evaluated()) { + ++it; + assert(iter_move(it) == 2); + } } { - auto iter1 = forward_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - assert(std::ranges::iter_move(commonIter1) == 1); - ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&); + using It = const int*; + using CommonIt = std::common_iterator>; + int a[] = {1, 2, 3}; + CommonIt it = CommonIt(It(a)); + ASSERT_NOEXCEPT(iter_move(it)); + ASSERT_NOEXCEPT(std::ranges::iter_move(it)); + ASSERT_SAME_TYPE(decltype(iter_move(it)), const int&&); + ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(it)), const int&&); + assert(iter_move(it) == 1); + if (!std::is_constant_evaluated()) { + ++it; + assert(iter_move(it) == 2); + } } { - auto iter1 = random_access_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - assert(std::ranges::iter_move(commonIter1) == 1); - ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&); + using It = IterMovingIt; + using CommonIt = std::common_iterator; + CommonIt it = CommonIt(It()); + ASSERT_NOT_NOEXCEPT(iter_move(it)); + ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(it)); + ASSERT_SAME_TYPE(decltype(iter_move(it)), int); + ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(it)), int); + assert(iter_move(it) == 42); + if (!std::is_constant_evaluated()) { + ++it; + assert(iter_move(it) == 42); + } } + return true; } int main(int, char**) { test(); + static_assert(test()); return 0; } diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp @@ -10,55 +10,114 @@ // UNSUPPORTED: libcpp-no-concepts // template I2, class S2> -// friend void iter_swap(const common_iterator& x, const common_iterator& y) +// friend constexpr void iter_swap(const common_iterator& x, const common_iterator& y) // noexcept(noexcept(ranges::iter_swap(declval(), declval()))); #include #include +#include +#include "test_iterators.h" #include "test_macros.h" -#include "types.h" -void test() { - int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; +template +struct IterSwappingIt { + using value_type = int; + using difference_type = int; + constexpr explicit IterSwappingIt(int *swaps) : swaps_(swaps) {} + IterSwappingIt(const IterSwappingIt&); // copyable, but this test shouldn't make copies + IterSwappingIt(IterSwappingIt&&) = default; + IterSwappingIt& operator=(const IterSwappingIt&); + int& operator*() const; + constexpr IterSwappingIt& operator++() { return *this; } + IterSwappingIt operator++(int); + template + friend constexpr int iter_swap(const IterSwappingIt& lhs, const IterSwappingIt& rhs) { + *lhs.swaps_ += 10; + *rhs.swaps_ += 1; + return 42; // should be accepted but ignored + } + + bool operator==(std::default_sentinel_t) const; + + int *swaps_ = nullptr; +}; +static_assert(std::input_iterator>); +static_assert(std::indirectly_swappable, IterSwappingIt<0>>); +static_assert(std::indirectly_swappable, IterSwappingIt<1>>); + +constexpr bool test() { { - auto iter1 = cpp17_input_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonIter2 = std::common_iterator>(iter1); - for (auto i = 0; i < 4; ++i) ++commonIter2; - assert(*commonIter2 == 5); - std::ranges::iter_swap(commonIter1, commonIter2); - assert(*commonIter1 == 5); - assert(*commonIter2 == 1); - std::ranges::iter_swap(commonIter2, commonIter1); + using It = int*; + using CommonIt = std::common_iterator>; + static_assert(std::indirectly_swappable); + + int a[] = {1, 2, 3}; + CommonIt it = CommonIt(It(a)); + CommonIt jt = CommonIt(It(a+1)); + ASSERT_NOEXCEPT(iter_swap(it, jt)); + ASSERT_SAME_TYPE(decltype(iter_swap(it, jt)), void); + iter_swap(it, jt); + assert(a[0] == 2); + assert(a[1] == 1); } { - auto iter1 = forward_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonIter2 = std::common_iterator>(iter1); - for (auto i = 0; i < 4; ++i) ++commonIter2; - assert(*commonIter2 == 5); - std::ranges::iter_swap(commonIter1, commonIter2); - assert(*commonIter1 == 5); - assert(*commonIter2 == 1); - std::ranges::iter_swap(commonIter2, commonIter1); + using It = const int*; + using CommonIt = std::common_iterator>; + static_assert(!std::indirectly_swappable); } { - auto iter1 = random_access_iterator(buffer); - auto commonIter1 = std::common_iterator>(iter1); - auto commonIter2 = std::common_iterator>(iter1); - for (auto i = 0; i < 4; ++i) ++commonIter2; - assert(*commonIter2 == 5); - std::ranges::iter_swap(commonIter1, commonIter2); - assert(*commonIter1 == 5); - assert(*commonIter2 == 1); - std::ranges::iter_swap(commonIter2, commonIter1); + using It = IterSwappingIt<0>; + using CommonIt = std::common_iterator; + static_assert(std::indirectly_swappable); + + int iswaps = 100; + int jswaps = 100; + CommonIt it = CommonIt(It(&iswaps)); + CommonIt jt = CommonIt(It(&jswaps)); + ASSERT_NOT_NOEXCEPT(iter_swap(it, jt)); + ASSERT_SAME_TYPE(decltype(iter_swap(it, jt)), void); + iter_swap(it, jt); // lvalue iterators + assert(iswaps == 110); + assert(jswaps == 101); + iter_swap(CommonIt(It(&iswaps)), CommonIt(It(&jswaps))); // rvalue iterators + assert(iswaps == 120); + assert(jswaps == 102); + std::ranges::iter_swap(it, jt); + assert(iswaps == 130); + assert(jswaps == 103); + } + { + using It = IterSwappingIt<0>; + using Jt = IterSwappingIt<1>; + static_assert(std::indirectly_swappable); + using CommonIt = std::common_iterator; + using CommonJt = std::common_iterator; + static_assert(std::indirectly_swappable); + + int iswaps = 100; + int jswaps = 100; + CommonIt it = CommonIt(It(&iswaps)); + CommonJt jt = CommonJt(Jt(&jswaps)); + ASSERT_NOT_NOEXCEPT(iter_swap(it, jt)); + ASSERT_SAME_TYPE(decltype(iter_swap(it, jt)), void); + iter_swap(it, jt); // lvalue iterators + assert(iswaps == 110); + assert(jswaps == 101); + iter_swap(CommonIt(It(&iswaps)), CommonJt(Jt(&jswaps))); // rvalue iterators + assert(iswaps == 120); + assert(jswaps == 102); + std::ranges::iter_swap(it, jt); + assert(iswaps == 130); + assert(jswaps == 103); } + return true; } int main(int, char**) { test(); + static_assert(test()); return 0; } diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h --- a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h +++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h @@ -157,32 +157,6 @@ } }; -template -class convertible_iterator -{ - It it_; - -public: - typedef std::input_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef It pointer; - typedef typename std::iterator_traits::reference reference; - - constexpr It base() const {return it_;} - - convertible_iterator() = default; - explicit constexpr convertible_iterator(It it) : it_(it) {} - - constexpr reference operator*() const {return *it_;} - - constexpr convertible_iterator& operator++() {++it_; return *this;} - constexpr convertible_iterator operator++(int) - {convertible_iterator tmp(*this); ++(*this); return tmp;} - - operator forward_iterator() const { return forward_iterator(it_); } -}; - template class non_const_deref_iterator { diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -117,38 +117,6 @@ void operator,(T const &) = delete; }; -template -class non_default_constructible_iterator -{ - It it_; - - template friend class non_default_constructible_iterator; -public: - typedef std::input_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef It pointer; - typedef typename std::iterator_traits::reference reference; - - non_default_constructible_iterator() = delete; - - TEST_CONSTEXPR explicit non_default_constructible_iterator(It it) : it_(it) {} - template - TEST_CONSTEXPR non_default_constructible_iterator(const non_default_constructible_iterator& u) : it_(u.it_) {} - - TEST_CONSTEXPR reference operator*() const {return *it_;} - TEST_CONSTEXPR pointer operator->() const {return it_;} - - TEST_CONSTEXPR_CXX14 non_default_constructible_iterator& operator++() {++it_; return *this;} - TEST_CONSTEXPR_CXX14 non_default_constructible_iterator operator++(int) {return non_default_constructible_iterator(it_++);} - - friend TEST_CONSTEXPR bool operator==(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) {return x.it_ == y.it_;} - friend TEST_CONSTEXPR bool operator!=(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) {return x.it_ != y.it_;} - - template - void operator,(T const &) = delete; -}; - template class bidirectional_iterator {