//===----------------------------------------------------------------------===//
//
// 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
// template<class In>
// concept indirectly_readable;
#include <concepts>
#include <iterator>
#include <type_traits>
#include "read_write.h"
template <class In>
constexpr bool check_indirectly_readable() {
constexpr bool result = std::indirectly_readable<In>;
static_assert(std::indirectly_readable<In const> == result);
static_assert(std::indirectly_readable<In volatile> == result);
static_assert(std::indirectly_readable<In const volatile> == result);
static_assert(std::indirectly_readable<In const&> == result);
static_assert(std::indirectly_readable<In volatile&> == result);
static_assert(std::indirectly_readable<In const volatile&> == result);
static_assert(std::indirectly_readable<In const&&> == result);
static_assert(std::indirectly_readable<In volatile&&> == result);
static_assert(std::indirectly_readable<In const volatile&&> == result);
return result;
}
static_assert(!check_indirectly_readable<void*>());
static_assert(!check_indirectly_readable<void const*>());
static_assert(!check_indirectly_readable<void volatile*>());
static_assert(!check_indirectly_readable<void const volatile*>());
static_assert(check_indirectly_readable<int*>());
static_assert(check_indirectly_readable<int const*>());
static_assert(check_indirectly_readable<int volatile*>());
static_assert(check_indirectly_readable<int const volatile*>());
static_assert(check_indirectly_readable<value_type_indirection>());
static_assert(check_indirectly_readable<element_type_indirection>());
static_assert(check_indirectly_readable<proxy_indirection>());
static_assert(check_indirectly_readable<read_only_indirection>());
struct indirection_mismatch {
using value_type = int;
float& operator*() const;
};
static_assert(!std::same_as<std::iter_value_t<indirection_mismatch>, std::iter_reference_t<indirection_mismatch> > &&
check_indirectly_readable<indirection_mismatch>());
static_assert(!check_indirectly_readable<missing_dereference>());
// `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<iter_move_mismatch>());
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<indirection_and_iter_move_mismatch>());
struct missing_iter_value_t {
int operator*() const;
};
static_assert(!check_indirectly_readable<missing_iter_value_t>());
struct unrelated_lvalue_ref_and_rvalue_ref {};
struct iter_ref1 {};
template <>
struct std::common_reference<iter_ref1&, iter_ref1&&> {};
template <>
struct std::common_reference<iter_ref1&&, iter_ref1&> {};
static_assert(!std::common_reference_with<iter_ref1&, iter_ref1&&>);
struct bad_iter_reference_t {
using value_type = int;
iter_ref1& operator*() const;
};
static_assert(!check_indirectly_readable<bad_iter_reference_t>());
struct iter_ref2 {};
struct iter_rvalue_ref {};
struct unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue {
using value_type = iter_ref2;
iter_ref2& operator*() const;
friend iter_rvalue_ref&& iter_move(unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue);
};
static_assert(!check_indirectly_readable<unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue>());
struct iter_ref3 {
operator iter_rvalue_ref() const;
};
template <template <class> class XQual, template <class> class YQual>
struct std::basic_common_reference<iter_ref3, iter_rvalue_ref, XQual, YQual> {
using type = iter_rvalue_ref;
};
template <template <class> class XQual, template <class> class YQual>
struct std::basic_common_reference<iter_rvalue_ref, iter_ref3, XQual, YQual> {
using type = iter_rvalue_ref;
};
static_assert(std::common_reference_with<iter_ref3&&, iter_rvalue_ref&&>);
struct different_reference_types_with_common_reference {
using value_type = iter_ref3;
iter_ref3& operator*() const;
friend iter_rvalue_ref&& iter_move(different_reference_types_with_common_reference);
};
static_assert(check_indirectly_readable<different_reference_types_with_common_reference>());
struct iter_ref4 {
operator iter_rvalue_ref() const;
};
template <template <class> class XQual, template <class> class YQual>
struct std::basic_common_reference<iter_ref4, iter_rvalue_ref, XQual, YQual> {
using type = iter_rvalue_ref;
};
template <template <class> class XQual, template <class> class YQual>
struct std::basic_common_reference<iter_rvalue_ref, iter_ref4, XQual, YQual> {
using type = iter_rvalue_ref;
};
// FIXME: This is UB according to [meta.rqmts], and there is no exception for common_reference.
template <>
struct std::common_reference<iter_ref4 const&, iter_rvalue_ref&&> {};
template <>
struct std::common_reference<iter_rvalue_ref&&, iter_ref4 const&> {};
static_assert(std::common_reference_with<iter_ref4&&, iter_rvalue_ref&&>);
static_assert(!std::common_reference_with<iter_ref4 const&, iter_rvalue_ref&&>);
struct different_reference_types_without_common_reference_to_const {
using value_type = iter_ref4;
iter_ref4& operator*() const;
friend iter_rvalue_ref&& iter_move(different_reference_types_without_common_reference_to_const);
};
static_assert(!check_indirectly_readable<different_reference_types_without_common_reference_to_const>());
struct non_const_deref {
int& operator*();
};
static_assert(!check_indirectly_readable<non_const_deref>());
struct not_referenceable {
using value_type = void;
void operator*() const;
};
static_assert(!std::indirectly_readable<not_referenceable>);
struct legacy_output_iterator {
using value_type = void;
legacy_output_iterator& operator*();
};
static_assert(!std::indirectly_readable<legacy_output_iterator>);
struct S {};
static_assert(!std::indirectly_readable<S>);
static_assert(!std::indirectly_readable<int S::*>);
static_assert(!std::indirectly_readable<int (S::*)()>);
static_assert(!std::indirectly_readable<int (S::*)() noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() &>);
static_assert(!std::indirectly_readable<int (S::*)() & noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() &&>);
static_assert(!std::indirectly_readable < int (S::*)() && noexcept >);
static_assert(!std::indirectly_readable<int (S::*)() const>);
static_assert(!std::indirectly_readable<int (S::*)() const noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() const&>);
static_assert(!std::indirectly_readable<int (S::*)() const & noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() const&&>);
static_assert(!std::indirectly_readable < int (S::*)() const&& noexcept >);
static_assert(!std::indirectly_readable<int (S::*)() volatile>);
static_assert(!std::indirectly_readable<int (S::*)() volatile noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() volatile&>);
static_assert(!std::indirectly_readable<int (S::*)() volatile & noexcept>);
static_assert(!std::indirectly_readable<int (S::*)() volatile&&>);
static_assert(!std::indirectly_readable < int (S::*)() volatile&& noexcept >);