[libcxx-commits] [libcxx] 58b29a4 - [libc++] Add all indirect callable concepts and projected
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Fri May 28 07:09:11 PDT 2021
Author: Louis Dionne
Date: 2021-05-28T10:10:44-04:00
New Revision: 58b29a4efc2212802f205e1614d58fa3c337105c
URL: https://github.com/llvm/llvm-project/commit/58b29a4efc2212802f205e1614d58fa3c337105c
DIFF: https://github.com/llvm/llvm-project/commit/58b29a4efc2212802f205e1614d58fa3c337105c.diff
LOG: [libc++] Add all indirect callable concepts and projected
Differential Revision: https://reviews.llvm.org/D101277
Added:
libcxx/include/__iterator/indirect_concepts.h
libcxx/include/__iterator/projected.h
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp
libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp
libcxx/test/support/indirectly_readable.h
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__iterator/concepts.h
libcxx/include/iterator
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index f752fabc8506e..e5ae54b225a8a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -17,10 +17,12 @@ set(files
__iterator/advance.h
__iterator/concepts.h
__iterator/incrementable_traits.h
+ __iterator/indirect_concepts.h
__iterator/iter_move.h
__iterator/iterator_traits.h
__iterator/next.h
__iterator/prev.h
+ __iterator/projected.h
__iterator/readable_traits.h
__libcpp_version
__locale
diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index 283e39be1a475..654d27bf250bf 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -17,6 +17,7 @@
#include <__iterator/readable_traits.h>
#include <__memory/pointer_traits.h>
#include <concepts>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
@@ -48,6 +49,9 @@ concept __indirectly_readable_impl =
template<class _In>
concept indirectly_readable = __indirectly_readable_impl<remove_cvref_t<_In> >;
+template<indirectly_readable _Tp>
+using iter_common_reference_t = common_reference_t<iter_reference_t<_Tp>, iter_value_t<_Tp>&>;
+
// [iterator.concept.writable]
template<class _Out, class _Tp>
concept indirectly_writable =
diff --git a/libcxx/include/__iterator/indirect_concepts.h b/libcxx/include/__iterator/indirect_concepts.h
new file mode 100644
index 0000000000000..d0ec08c143065
--- /dev/null
+++ b/libcxx/include/__iterator/indirect_concepts.h
@@ -0,0 +1,99 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___ITERATOR_INDIRECT_CONCEPTS_H
+#define _LIBCPP___ITERATOR_INDIRECT_CONCEPTS_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <concepts>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+template<class _Fp, class _It>
+concept indirectly_unary_invocable =
+ indirectly_readable<_It> &&
+ copy_constructible<_Fp> &&
+ invocable<_Fp&, iter_value_t<_It>&> &&
+ invocable<_Fp&, iter_reference_t<_It>> &&
+ invocable<_Fp&, iter_common_reference_t<_It>> &&
+ common_reference_with<
+ invoke_result_t<_Fp&, iter_value_t<_It>&>,
+ invoke_result_t<_Fp&, iter_reference_t<_It>>>;
+
+template<class _Fp, class _It>
+concept indirectly_regular_unary_invocable =
+ indirectly_readable<_It> &&
+ copy_constructible<_Fp> &&
+ regular_invocable<_Fp&, iter_value_t<_It>&> &&
+ regular_invocable<_Fp&, iter_reference_t<_It>> &&
+ regular_invocable<_Fp&, iter_common_reference_t<_It>> &&
+ common_reference_with<
+ invoke_result_t<_Fp&, iter_value_t<_It>&>,
+ invoke_result_t<_Fp&, iter_reference_t<_It>>>;
+
+template<class _Fp, class _It>
+concept indirect_unary_predicate =
+ indirectly_readable<_It> &&
+ copy_constructible<_Fp> &&
+ predicate<_Fp&, iter_value_t<_It>&> &&
+ predicate<_Fp&, iter_reference_t<_It>> &&
+ predicate<_Fp&, iter_common_reference_t<_It>>;
+
+template<class _Fp, class _It1, class _It2>
+concept indirect_binary_predicate =
+ indirectly_readable<_It1> && indirectly_readable<_It2> &&
+ copy_constructible<_Fp> &&
+ predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
+ predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
+ predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
+ predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
+ predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
+
+template<class _Fp, class _It1, class _It2 = _It1>
+concept indirect_equivalence_relation =
+ indirectly_readable<_It1> && indirectly_readable<_It2> &&
+ copy_constructible<_Fp> &&
+ equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
+ equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
+ equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
+ equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
+ equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
+
+template<class _Fp, class _It1, class _It2 = _It1>
+concept indirect_strict_weak_order =
+ indirectly_readable<_It1> && indirectly_readable<_It2> &&
+ copy_constructible<_Fp> &&
+ strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
+ strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
+ strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
+ strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
+ strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
+
+template<class _Fp, class... _Its>
+ requires (indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...>
+using indirect_result_t = invoke_result_t<_Fp, iter_reference_t<_Its>...>;
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_INDIRECT_CONCEPTS_H
diff --git a/libcxx/include/__iterator/projected.h b/libcxx/include/__iterator/projected.h
new file mode 100644
index 0000000000000..8f2853f0f1256
--- /dev/null
+++ b/libcxx/include/__iterator/projected.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef _LIBCPP___ITERATOR_PROJECTED_H
+#define _LIBCPP___ITERATOR_PROJECTED_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/indirect_concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+template<indirectly_readable _It, indirectly_regular_unary_invocable<_It> _Proj>
+struct projected {
+ using value_type = remove_cvref_t<indirect_result_t<_Proj&, _It>>;
+ indirect_result_t<_Proj&, _It> operator*() const; // not defined
+};
+
+template<weakly_incrementable _It, class _Proj>
+struct incrementable_traits<projected<_It, _Proj>> {
+ using
diff erence_type = iter_
diff erence_t<_It>;
+};
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___ITERATOR_PROJECTED_H
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index e290a4922a294..d4be4826b234c 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -46,7 +46,11 @@ using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<T&>())); // s
// [iterator.concepts], iterator concepts
// [iterator.concept.readable], concept indirectly_readable
template<class In>
- concept indirectly_readable = see below; // since C++20
+ concept indirectly_readable = see below; // since C++20
+
+template<indirectly_readable T>
+ using iter_common_reference_t =
+ common_reference_t<iter_reference_t<T>, iter_value_t<T>&>; // since C++20
// [iterator.concept.writable], concept indirectly_writable
template<class Out, class T>
@@ -91,6 +95,36 @@ template<class I>
template<class I>
concept random_access_iterator = see below; // since C++20
+// [indirectcallable]
+// [indirectcallable.indirectinvocable]
+template<class F, class I>
+ concept indirectly_unary_invocable = see below; // since C++20
+
+template<class F, class I>
+ concept indirectly_regular_unary_invocable = see below; // since C++20
+
+template<class F, class I>
+ concept indirect_unary_predicate = see below; // since C++20
+
+template<class F, class I1, class I2>
+ concept indirect_binary_predicate = see below; // since C++20
+
+template<class F, class I1, class I2 = I1>
+ concept indirect_equivalence_relation = see below; // since C++20
+
+template<class F, class I1, class I2 = I1>
+ concept indirect_strict_weak_order = see below; // since C++20
+
+template<class F, class... Is>
+ using indirect_result_t = see below; // since C++20
+
+// [projected], projected
+template<indirectly_readable I, indirectly_regular_unary_invocable<I> Proj>
+ struct projected; // since C++20
+
+template<weakly_incrementable I, indirectly_regular_unary_invocable<I> Proj>
+ struct incrementable_traits<projected<I, Proj>>; // since C++20
+
template<class Category, class T, class Distance = ptr
diff _t,
class Pointer = T*, class Reference = T&>
struct iterator // deprecated in C++17
@@ -486,10 +520,12 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#include <__iterator/advance.h>
#include <__iterator/concepts.h>
#include <__iterator/incrementable_traits.h>
+#include <__iterator/indirect_concepts.h>
#include <__iterator/iter_move.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
#include <__iterator/prev.h>
+#include <__iterator/projected.h>
#include <__iterator/readable_traits.h>
#include <__memory/addressof.h>
#include <__memory/pointer_traits.h>
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp
new file mode 100644
index 0000000000000..3894b66f7f9ce
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I1, class I2>
+// concept indirect_binary_predicate;
+
+#include <iterator>
+#include <type_traits>
+
+#include "indirectly_readable.h"
+
+using It1 = IndirectlyReadable<struct Token1>;
+using It2 = IndirectlyReadable<struct Token2>;
+
+template <class I1, class I2>
+struct GoodPredicate {
+ bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirect_binary_predicate<GoodPredicate<It1, It2>, It1, It2>);
+static_assert(std::indirect_binary_predicate<bool(*)(int, float), int*, float*>);
+[[maybe_unused]] auto lambda = [](int i, int j) { return i < j; };
+static_assert(std::indirect_binary_predicate<decltype(lambda), int*, int*>);
+
+// Should fail when either of the iterators is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirect_binary_predicate<GoodPredicate<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>);
+static_assert(!std::indirect_binary_predicate<GoodPredicate<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>);
+
+// Should fail when the predicate is not copy constructible
+struct BadPredicate1 {
+ BadPredicate1(BadPredicate1 const&) = delete;
+ template <class T, class U> bool operator()(T const&, U const&) const;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate1, It1, It2>);
+
+// Should fail when the predicate can't be called with (iter_value_t&, iter_value_t&)
+struct BadPredicate2 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate2, It1, It2>);
+
+// Should fail when the predicate can't be called with (iter_value_t&, iter_reference_t)
+struct BadPredicate3 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate3, It1, It2>);
+
+// Should fail when the predicate can't be called with (iter_reference_t, iter_value_t&)
+struct BadPredicate4 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate4, It1, It2>);
+
+// Should fail when the predicate can't be called with (iter_reference_t, iter_reference_t)
+struct BadPredicate5 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate5, It1, It2>);
+
+// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t)
+struct BadPredicate6 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp
new file mode 100644
index 0000000000000..913ada3595dcd
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I1, class I2 = I1>
+// concept indirect_equivalence_relation;
+
+#include <iterator>
+#include <concepts>
+
+#include "indirectly_readable.h"
+
+using It1 = IndirectlyReadable<struct Token1>;
+using It2 = IndirectlyReadable<struct Token2>;
+
+template <class I1, class I2>
+struct GoodRelation {
+ bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I1>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I1>&) const;
+
+ bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_value_t<I1>&) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I2>) const;
+
+ bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_reference_t<I1>) const;
+ bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I1>) const;
+
+ bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I1>) const;
+
+ bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I1>) const;
+ bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I2>) const;
+ bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const;
+ bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I1>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirect_equivalence_relation<GoodRelation<It1, It2>, It1, It2>);
+static_assert(std::indirect_equivalence_relation<bool(*)(int, long), int*, long*>);
+[[maybe_unused]] auto lambda = [](int i, long j) { return i == j; };
+static_assert(std::indirect_equivalence_relation<decltype(lambda), int*, long*>);
+
+// Should fail when either of the iterators is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirect_equivalence_relation<GoodRelation<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>);
+static_assert(!std::indirect_equivalence_relation<GoodRelation<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>);
+
+// Should fail when the function is not copy constructible
+struct BadRelation1 {
+ BadRelation1(BadRelation1 const&) = delete;
+ template <class T, class U> bool operator()(T const&, U const&) const;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation1, It1, It2>);
+
+// Should fail when the function can't be called with (iter_value_t&, iter_value_t&)
+struct BadRelation2 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation2, It1, It2>);
+
+// Should fail when the function can't be called with (iter_value_t&, iter_reference_t)
+struct BadRelation3 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation3, It1, It2>);
+
+// Should fail when the function can't be called with (iter_reference_t, iter_value_t&)
+struct BadRelation4 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation4, It1, It2>);
+
+// Should fail when the function can't be called with (iter_reference_t, iter_reference_t)
+struct BadRelation5 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>);
+
+// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
+struct BadRelation6 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp
new file mode 100644
index 0000000000000..8811f75456a10
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_result_t.compile.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// indirect_result_t
+
+#include <iterator>
+#include <concepts>
+
+static_assert(std::same_as<std::indirect_result_t<int (*)(int), int*>, int>);
+static_assert(std::same_as<std::indirect_result_t<double (*)(int const&, float), int const*, float*>, double>);
+
+struct S { };
+static_assert(std::same_as<std::indirect_result_t<S (&)(int), int*>, S>);
+static_assert(std::same_as<std::indirect_result_t<long S::*, S*>, long&>);
+static_assert(std::same_as<std::indirect_result_t<S && (S::*)(), S*>, S&&>);
+static_assert(std::same_as<std::indirect_result_t<int S::* (S::*)(int) const, S*, int*>, int S::*>);
+
+template <class F, class... Is>
+constexpr bool has_indirect_result = requires {
+ typename std::indirect_result_t<F, Is...>;
+};
+
+static_assert(!has_indirect_result<int (*)(int), int>); // int isn't indirectly_readable
+static_assert(!has_indirect_result<int, int*>); // int isn't invocable
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp
new file mode 100644
index 0000000000000..8a6598e840aa8
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I1, class I2 = I1>
+// concept indirect_strict_weak_order;
+
+#include <iterator>
+#include <concepts>
+
+#include "indirectly_readable.h"
+
+using It1 = IndirectlyReadable<struct Token1>;
+using It2 = IndirectlyReadable<struct Token2>;
+
+template <class I1, class I2>
+struct GoodOrder {
+ bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I1>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I1>&, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_value_t<I1>&) const;
+
+ bool operator()(std::iter_value_t<I1>&, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_value_t<I1>&) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I2>) const;
+
+ bool operator()(std::iter_reference_t<I1>, std::iter_value_t<I2>&) const;
+ bool operator()(std::iter_value_t<I2>&, std::iter_reference_t<I1>) const;
+ bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I1>) const;
+
+ bool operator()(std::iter_reference_t<I1>, std::iter_reference_t<I2>) const;
+ bool operator()(std::iter_reference_t<I2>, std::iter_reference_t<I1>) const;
+
+ bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I1>) const;
+ bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I2>) const;
+ bool operator()(std::iter_common_reference_t<I1>, std::iter_common_reference_t<I2>) const;
+ bool operator()(std::iter_common_reference_t<I2>, std::iter_common_reference_t<I1>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirect_strict_weak_order<GoodOrder<It1, It2>, It1, It2>);
+static_assert(std::indirect_strict_weak_order<bool(*)(int, long), int*, long*>);
+[[maybe_unused]] auto lambda = [](int i, long j) { return i < j; };
+static_assert(std::indirect_strict_weak_order<decltype(lambda), int*, long*>);
+
+// Should fail when either of the iterators is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirect_strict_weak_order<GoodOrder<It1, NotIndirectlyReadable>, It1, NotIndirectlyReadable>);
+static_assert(!std::indirect_strict_weak_order<GoodOrder<NotIndirectlyReadable, It2>, NotIndirectlyReadable, It2>);
+
+// Should fail when the function is not copy constructible
+struct BadOrder1 {
+ BadOrder1(BadOrder1 const&) = delete;
+ template <class T, class U> bool operator()(T const&, U const&) const;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder1, It1, It2>);
+
+// Should fail when the function can't be called with (iter_value_t&, iter_value_t&)
+struct BadOrder2 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder2, It1, It2>);
+
+// Should fail when the function can't be called with (iter_value_t&, iter_reference_t)
+struct BadOrder3 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_value_t<It1>&, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder3, It1, It2>);
+
+// Should fail when the function can't be called with (iter_reference_t, iter_value_t&)
+struct BadOrder4 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_value_t<It2>&) const = delete;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder4, It1, It2>);
+
+// Should fail when the function can't be called with (iter_reference_t, iter_reference_t)
+struct BadOrder5 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_reference_t<It1>, std::iter_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder5, It1, It2>);
+
+// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
+struct BadOrder6 {
+ template <class T, class U> bool operator()(T const&, U const&) const;
+ bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
+};
+static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp
new file mode 100644
index 0000000000000..8cb5cc1ab36a2
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I>
+// concept indirect_unary_predicate;
+
+#include <iterator>
+#include <type_traits>
+
+#include "indirectly_readable.h"
+
+using It = IndirectlyReadable<struct Token>;
+
+template <class I>
+struct GoodPredicate {
+ bool operator()(std::iter_reference_t<I>) const;
+ bool operator()(std::iter_value_t<I>&) const;
+ bool operator()(std::iter_common_reference_t<I>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirect_unary_predicate<GoodPredicate<It>, It>);
+static_assert(std::indirect_unary_predicate<bool(*)(int), int*>);
+[[maybe_unused]] auto lambda = [](int i) { return i % 2 == 0; };
+static_assert(std::indirect_unary_predicate<decltype(lambda), int*>);
+
+// Should fail when the iterator is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirect_unary_predicate<GoodPredicate<NotIndirectlyReadable>, NotIndirectlyReadable>);
+
+// Should fail when the predicate is not copy constructible
+struct BadPredicate1 {
+ BadPredicate1(BadPredicate1 const&) = delete;
+ template <class T> bool operator()(T const&) const;
+};
+static_assert(!std::indirect_unary_predicate<BadPredicate1, It>);
+
+// Should fail when the predicate can't be called with std::iter_value_t<It>&
+struct BadPredicate2 {
+ template <class T> bool operator()(T const&) const;
+ bool operator()(std::iter_value_t<It>&) const = delete;
+};
+static_assert(!std::indirect_unary_predicate<BadPredicate2, It>);
+
+// Should fail when the predicate can't be called with std::iter_reference_t<It>
+struct BadPredicate3 {
+ template <class T> bool operator()(T const&) const;
+ bool operator()(std::iter_reference_t<It>) const = delete;
+};
+static_assert(!std::indirect_unary_predicate<BadPredicate3, It>);
+
+// Should fail when the predicate can't be called with std::iter_common_reference_t<It>
+struct BadPredicate4 {
+ template <class T> bool operator()(T const&) const;
+ bool operator()(std::iter_common_reference_t<It>) const = delete;
+};
+static_assert(!std::indirect_unary_predicate<BadPredicate4, It>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp
new file mode 100644
index 0000000000000..d30901c307c3d
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I>
+// concept indirectly_regular_unary_invocable;
+
+#include <iterator>
+#include <concepts>
+
+#include "indirectly_readable.h"
+
+using It = IndirectlyReadable<struct Token>;
+using R1 = T1<struct ReturnToken>;
+using R2 = T2<struct ReturnToken>;
+
+template <class I>
+struct GoodInvocable {
+ R1 operator()(std::iter_value_t<I>&) const;
+ R2 operator()(std::iter_reference_t<I>) const;
+ R2 operator()(std::iter_common_reference_t<I>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirectly_regular_unary_invocable<GoodInvocable<It>, It>);
+
+// Should fail when the iterator is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirectly_regular_unary_invocable<GoodInvocable<NotIndirectlyReadable>, NotIndirectlyReadable>);
+
+// Should fail when the invocable is not copy constructible
+struct BadInvocable1 {
+ BadInvocable1(BadInvocable1 const&) = delete;
+ template <class T> R1 operator()(T const&) const;
+};
+static_assert(!std::indirectly_regular_unary_invocable<BadInvocable1, It>);
+
+// Should fail when the invocable can't be called with (iter_value_t&)
+struct BadInvocable2 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_value_t<It>&) const = delete;
+};
+static_assert(!std::indirectly_regular_unary_invocable<BadInvocable2, It>);
+
+// Should fail when the invocable can't be called with (iter_reference_t)
+struct BadInvocable3 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_reference_t<It>) const = delete;
+};
+static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>);
+
+// Should fail when the invocable can't be called with (iter_common_reference_t)
+struct BadInvocable4 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_common_reference_t<It>) const = delete;
+};
+static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>);
+
+// Should fail when the invocable doesn't have a common reference between its return types
+struct BadInvocable5 {
+ R1 operator()(std::iter_value_t<It>&) const;
+ struct Unrelated { };
+ Unrelated operator()(std::iter_reference_t<It>) const;
+ R1 operator()(std::iter_common_reference_t<It>) const;
+};
+static_assert(!std::indirectly_regular_unary_invocable<BadInvocable5, It>);
+
+// Various tests with callables
+struct S;
+static_assert(std::indirectly_regular_unary_invocable<int (*)(int), int*>);
+static_assert(std::indirectly_regular_unary_invocable<int (&)(int), int*>);
+static_assert(std::indirectly_regular_unary_invocable<int S::*, S*>);
+static_assert(std::indirectly_regular_unary_invocable<int (S::*)(), S*>);
+static_assert(std::indirectly_regular_unary_invocable<int (S::*)() const, S*>);
+static_assert(std::indirectly_regular_unary_invocable<void(*)(int), int*>);
+
+static_assert(!std::indirectly_regular_unary_invocable<int(int), int*>); // not move constructible
+static_assert(!std::indirectly_regular_unary_invocable<int (*)(int*, int*), int*>);
+static_assert(!std::indirectly_regular_unary_invocable<int (&)(int*, int*), int*>);
+static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*), S*>);
+static_assert(!std::indirectly_regular_unary_invocable<int (S::*)(int*) const, S*>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp
new file mode 100644
index 0000000000000..a1f282d0808a0
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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<class F, class I>
+// concept indirectly_unary_invocable;
+
+#include <iterator>
+#include <concepts>
+
+#include "indirectly_readable.h"
+
+using It = IndirectlyReadable<struct Token>;
+using R1 = T1<struct ReturnToken>;
+using R2 = T2<struct ReturnToken>;
+
+template <class I>
+struct GoodInvocable {
+ R1 operator()(std::iter_value_t<I>&) const;
+ R2 operator()(std::iter_reference_t<I>) const;
+ R2 operator()(std::iter_common_reference_t<I>) const;
+};
+
+// Should work when all constraints are satisfied
+static_assert(std::indirectly_unary_invocable<GoodInvocable<It>, It>);
+
+// Should fail when the iterator is not indirectly_readable
+struct NotIndirectlyReadable { };
+static_assert(!std::indirectly_unary_invocable<GoodInvocable<NotIndirectlyReadable>, NotIndirectlyReadable>);
+
+// Should fail when the invocable is not copy constructible
+struct BadInvocable1 {
+ BadInvocable1(BadInvocable1 const&) = delete;
+ template <class T> R1 operator()(T const&) const;
+};
+static_assert(!std::indirectly_unary_invocable<BadInvocable1, It>);
+
+// Should fail when the invocable can't be called with (iter_value_t&)
+struct BadInvocable2 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_value_t<It>&) const = delete;
+};
+static_assert(!std::indirectly_unary_invocable<BadInvocable2, It>);
+
+// Should fail when the invocable can't be called with (iter_reference_t)
+struct BadInvocable3 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_reference_t<It>) const = delete;
+};
+static_assert(!std::indirectly_unary_invocable<BadInvocable3, It>);
+
+// Should fail when the invocable can't be called with (iter_common_reference_t)
+struct BadInvocable4 {
+ template <class T> R1 operator()(T const&) const;
+ R1 operator()(std::iter_common_reference_t<It>) const = delete;
+};
+static_assert(!std::indirectly_unary_invocable<BadInvocable4, It>);
+
+// Should fail when the invocable doesn't have a common reference between its return types
+struct BadInvocable5 {
+ R1 operator()(std::iter_value_t<It>&) const;
+ struct Unrelated { };
+ Unrelated operator()(std::iter_reference_t<It>) const;
+ R1 operator()(std::iter_common_reference_t<It>) const;
+};
+static_assert(!std::indirectly_unary_invocable<BadInvocable5, It>);
+
+// Various tests with callables
+struct S;
+static_assert(std::indirectly_unary_invocable<int (*)(int), int*>);
+static_assert(std::indirectly_unary_invocable<int (&)(int), int*>);
+static_assert(std::indirectly_unary_invocable<int S::*, S*>);
+static_assert(std::indirectly_unary_invocable<int (S::*)(), S*>);
+static_assert(std::indirectly_unary_invocable<int (S::*)() const, S*>);
+static_assert(std::indirectly_unary_invocable<void(*)(int), int*>);
+
+static_assert(!std::indirectly_unary_invocable<int(int), int*>); // not move constructible
+static_assert(!std::indirectly_unary_invocable<int (*)(int*, int*), int*>);
+static_assert(!std::indirectly_unary_invocable<int (&)(int*, int*), int*>);
+static_assert(!std::indirectly_unary_invocable<int (S::*)(int*), S*>);
+static_assert(!std::indirectly_unary_invocable<int (S::*)(int*) const, S*>);
diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp
new file mode 100644
index 0000000000000..fa96b629b20b3
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/projected/projected.compile.pass.cpp
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// projected
+
+#include <iterator>
+
+#include <concepts>
+#include <functional>
+
+#include "test_iterators.h"
+
+using IntPtr = std::projected<int const*, std::identity>;
+static_assert(std::same_as<IntPtr::value_type, int>);
+static_assert(std::same_as<decltype(*std::declval<IntPtr>()), int const&>);
+static_assert(std::same_as<std::iter_
diff erence_t<IntPtr>, std::ptr
diff _t>);
+
+struct S { };
+
+using Cpp17InputIterator = std::projected<cpp17_input_iterator<S*>, int S::*>;
+static_assert(std::same_as<Cpp17InputIterator::value_type, int>);
+static_assert(std::same_as<decltype(*std::declval<Cpp17InputIterator>()), int&>);
+static_assert(std::same_as<std::iter_
diff erence_t<Cpp17InputIterator>, std::ptr
diff _t>);
+
+using Cpp20InputIterator = std::projected<cpp20_input_iterator<S*>, int S::*>;
+static_assert(std::same_as<Cpp20InputIterator::value_type, int>);
+static_assert(std::same_as<decltype(*std::declval<Cpp20InputIterator>()), int&>);
+static_assert(std::same_as<std::iter_
diff erence_t<Cpp20InputIterator>, std::ptr
diff _t>);
+
+using ForwardIterator = std::projected<forward_iterator<S*>, int (S::*)()>;
+static_assert(std::same_as<ForwardIterator::value_type, int>);
+static_assert(std::same_as<decltype(*std::declval<ForwardIterator>()), int>);
+static_assert(std::same_as<std::iter_
diff erence_t<ForwardIterator>, std::ptr
diff _t>);
+
+using BidirectionalIterator = std::projected<bidirectional_iterator<S*>, S* (S::*)() const>;
+static_assert(std::same_as<BidirectionalIterator::value_type, S*>);
+static_assert(std::same_as<decltype(*std::declval<BidirectionalIterator>()), S*>);
+static_assert(std::same_as<std::iter_
diff erence_t<BidirectionalIterator>, std::ptr
diff _t>);
+
+using RandomAccessIterator = std::projected<random_access_iterator<S*>, S && (S::*)()>;
+static_assert(std::same_as<RandomAccessIterator::value_type, S>);
+static_assert(std::same_as<decltype(*std::declval<RandomAccessIterator>()), S&&>);
+static_assert(std::same_as<std::iter_
diff erence_t<RandomAccessIterator>, std::ptr
diff _t>);
+
+using ContiguousIterator = std::projected<contiguous_iterator<S*>, S& (S::*)() const>;
+static_assert(std::same_as<ContiguousIterator::value_type, S>);
+static_assert(std::same_as<decltype(*std::declval<ContiguousIterator>()), S&>);
+static_assert(std::same_as<std::iter_
diff erence_t<ContiguousIterator>, std::ptr
diff _t>);
+
+template <class I, class F>
+constexpr bool projectable = requires {
+ typename std::projected<I, F>;
+};
+
+static_assert(!projectable<int, void (*)(int)>); // int isn't indirectly_readable
+static_assert(!projectable<S, void (*)(int)>); // S isn't weakly_incrementable
+static_assert(!projectable<int*, void(int)>); // void(int) doesn't satisfy indirectly_regular_unary_invcable
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp
new file mode 100644
index 0000000000000..300e626b141b7
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.readable/iter_common_reference_t.compile.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// iter_common_reference_t
+
+#include <iterator>
+
+#include <concepts>
+
+struct X { };
+
+// value_type and dereferencing are the same
+struct T1 {
+ using value_type = X;
+ X operator*() const;
+};
+static_assert(std::same_as<std::iter_common_reference_t<T1>, X>);
+
+// value_type and dereferencing are the same (modulo qualifiers)
+struct T2 {
+ using value_type = X;
+ X& operator*() const;
+};
+static_assert(std::same_as<std::iter_common_reference_t<T2>, X&>);
+
+// There's a custom common reference between value_type and the type of dereferencing
+struct A { };
+struct B { };
+struct Common { Common(A); Common(B); };
+template <template <class> class TQual, template <class> class QQual>
+struct std::basic_common_reference<A, B, TQual, QQual> {
+ using type = Common;
+};
+template <template <class> class TQual, template <class> class QQual>
+struct std::basic_common_reference<B, A, TQual, QQual>
+ : std::basic_common_reference<A, B, TQual, QQual>
+{ };
+
+struct T3 {
+ using value_type = A;
+ B&& operator*() const;
+};
+static_assert(std::same_as<std::iter_common_reference_t<T3>, Common>);
+
+// Make sure we're SFINAE-friendly
+template <class T>
+constexpr bool has_common_reference = requires {
+ typename std::iter_common_reference_t<T>;
+};
+struct NotIndirectlyReadable { };
+static_assert(!has_common_reference<NotIndirectlyReadable>);
diff --git a/libcxx/test/support/indirectly_readable.h b/libcxx/test/support/indirectly_readable.h
new file mode 100644
index 0000000000000..ad32e75e038b7
--- /dev/null
+++ b/libcxx/test/support/indirectly_readable.h
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H
+#define LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H
+
+#include <type_traits>
+
+template <class Token>
+struct Common { };
+
+template <class Token>
+struct T1 : Common<Token> { };
+
+template <class Token>
+struct T2 : Common<Token> { };
+
+template <template <class> class T1Qual, template <class> class T2Qual, class Token>
+struct std::basic_common_reference<T1<Token>, T2<Token>, T1Qual, T2Qual> {
+ using type = Common<Token>;
+};
+template <template <class> class T2Qual, template <class> class T1Qual, class Token>
+struct std::basic_common_reference<T2<Token>, T1<Token>, T2Qual, T1Qual>
+ : std::basic_common_reference<T1<Token>, T2<Token>, T1Qual, T2Qual>
+{ };
+
+template <class Token>
+struct IndirectlyReadable {
+ using value_type = T1<Token>;
+ T2<Token>& operator*() const;
+};
+
+#endif // LIBCXX_TEST_SUPPORT_INDIRECTLY_READABLE_H
More information about the libcxx-commits
mailing list