[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