diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -2506,6 +2506,23 @@ requires requires(_Tp& __t) { { ranges::iter_move(__t) } -> __can_reference; } using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<_Tp&>())); +// [iterator.concept.readable] +template +concept __indirectly_readable_impl = + requires(const _In __in) { + typename iter_value_t<_In>; + typename iter_reference_t<_In>; + typename iter_rvalue_reference_t<_In>; + { *__in } -> same_as>; + { ranges::iter_move(__in) } -> same_as>; + } && + common_reference_with&&, iter_value_t<_In>&> && + common_reference_with&&, iter_rvalue_reference_t<_In>&&> && + common_reference_with&&, const iter_value_t<_In>&>; + +template +concept indirectly_readable = __indirectly_readable_impl>; + #undef _LIBCPP_NOEXCEPT_RETURN #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/indirectly_readable.compile.pass.cpp @@ -0,0 +1,319 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// UNSUPPORTED: gcc-10 + +// template +// concept indirectly_readable; + +#include + +#include +#include +#include +#ifndef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../read_write.h" + +template +[[nodiscard]] constexpr bool check_indirectly_readable() { + constexpr bool result = std::indirectly_readable; + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + static_assert(std::indirectly_readable == result); + return result; +} + +static_assert(check_indirectly_readable()); + +struct alternative_indirection { + using element_type = long; + element_type& operator*() const; +}; +static_assert(check_indirectly_readable()); + +static_assert(check_indirectly_readable()); +static_assert(check_indirectly_readable()); + +struct indirection_mismatch { + using value_type = int; + float& operator*() const; +}; +static_assert(!std::same_as, + std::iter_reference_t > && + check_indirectly_readable()); +static_assert(!check_indirectly_readable()); + +// `iter_rvalue_reference_t` can't be missing unless the dereference operator is also missing. + +struct iter_move_mismatch { + using value_type = int; + value_type& operator*() const; + + friend float& iter_move(iter_move_mismatch&); +}; +static_assert(!check_indirectly_readable()); + +struct indirection_and_iter_move_mismatch { + using value_type = int; + float& operator*() const; + + friend unsigned long long& iter_move(indirection_and_iter_move_mismatch&); +}; +static_assert(!check_indirectly_readable()); + +struct missing_iter_value_t { + int operator*() const; +}; +static_assert(!check_indirectly_readable()); + +struct lvalue_ref_has_no_common_type_with_rvalue_ref {}; + +struct iter_ref1 {}; +namespace std { +template <> +struct common_reference {}; + +template <> +struct common_reference {}; +} // namespace std +static_assert(!std::common_reference_with); + +struct bad_iter_reference_t { + using value_type = int; + iter_ref1& operator*() const; +}; +static_assert(!check_indirectly_readable()); + +struct iter_ref2 {}; +struct iter_rvalue_ref {}; + +struct + no_common_reference_between_rvalue_ref_to_iter_ref_and_rvalue_ref_to_iter_rvalue_ref { + using value_type = iter_ref2; + iter_ref2& operator*() const; + friend iter_rvalue_ref&& iter_move( + no_common_reference_between_rvalue_ref_to_iter_ref_and_rvalue_ref_to_iter_rvalue_ref); +}; +static_assert( + !check_indirectly_readable< + no_common_reference_between_rvalue_ref_to_iter_ref_and_rvalue_ref_to_iter_rvalue_ref>()); + +struct iter_ref3 { + operator iter_rvalue_ref() const; +}; +namespace std { +template