diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -17,10 +17,12 @@
   __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
--- 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 @@
 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
--- /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
--- /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 difference_type = iter_difference_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
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -46,7 +46,11 @@
 // [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>
   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 = ptrdiff_t,
          class Pointer = T*, class Reference = T&>
 struct iterator                                            // deprecated in C++17
@@ -486,10 +520,12 @@
 #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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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_difference_t<IntPtr>, std::ptrdiff_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_difference_t<Cpp17InputIterator>, std::ptrdiff_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_difference_t<Cpp20InputIterator>, std::ptrdiff_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_difference_t<ForwardIterator>, std::ptrdiff_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_difference_t<BidirectionalIterator>, std::ptrdiff_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_difference_t<RandomAccessIterator>, std::ptrdiff_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_difference_t<ContiguousIterator>, std::ptrdiff_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
--- /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
--- /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