[libcxx-commits] [libcxx] e65d376 - [libc++][ranges] Implement `indirectly_copyable{, _storable}`.

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Wed Feb 2 13:28:00 PST 2022


Author: Konstantin Varlamov
Date: 2022-02-02T13:27:44-08:00
New Revision: e65d3760a31ba7e84e0f3b46cde2c9169e00cd19

URL: https://github.com/llvm/llvm-project/commit/e65d3760a31ba7e84e0f3b46cde2c9169e00cd19
DIFF: https://github.com/llvm/llvm-project/commit/e65d3760a31ba7e84e0f3b46cde2c9169e00cd19.diff

LOG: [libc++][ranges] Implement `indirectly_copyable{,_storable}`.

Also refactor tests for `indirectly_movable{,_storable}`.

Differential Revision: https://reviews.llvm.org/D118432

Added: 
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.subsumption.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.subsumption.compile.pass.cpp

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/__iterator/concepts.h
    libcxx/include/iterator
    libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/input.output/filesystems/class.directory_iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.compile.pass.cpp
    libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.subsumption.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/insert.iterators/back.insert.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/insert.iterators/front.insert.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/stream.iterators/istream.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/stream.iterators/ostream.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/iterators/stream.iterators/ostreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/utilities/memory/unique.ptr/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/iterator_concept_conformance.compile.pass.cpp
    libcxx/test/std/utilities/optional/iterator_concept_conformance.compile.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index bea73d28655f5..aefbd417e712d 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -59,8 +59,8 @@ Section,Description,Dependencies,Assignee,Complete
 `[projected] <https://wg21.link/projected>`_,`ranges::projected <https://llvm.org/D101277>`_,[iterator.concepts],Louis Dionne,✅
 `[common.alg.req] <https://wg21.link/common.alg.req>`_: pt. 1,"| `indirectly_movable <https://llvm.org/D102639>`_
 | `indirectly_movable_storable <https://llvm.org/D102639>`_
-| indirectly_copyable
-| indirectly_copyable_storable",[iterator.concepts],Zoe Carver,In progress
+| `indirectly_copyable <https://llvm.org/D118432>`_
+| `indirectly_copyable_storable <https://llvm.org/D118432>`_",[iterator.concepts],Zoe Carver and Konstantin Varlamov,✅
 `[common.alg.req] <https://wg21.link/common.alg.req>`_: pt. 2,`indirectly_swappable <https://llvm.org/D105304>`_,"| [iterator.concepts]
 | [iterator.cust.swap]",Zoe Carver,✅
 `[common.alg.req] <https://wg21.link/common.alg.req>`_: pt. 3,`indirectly_comparable <https://llvm.org/D116268>`_,[projected],Nikolas Klauser,✅

diff  --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h
index b7976abb76ef0..8f353751c9e5f 100644
--- a/libcxx/include/__iterator/concepts.h
+++ b/libcxx/include/__iterator/concepts.h
@@ -254,6 +254,22 @@ concept indirectly_movable_storable =
   constructible_from<iter_value_t<_In>, iter_rvalue_reference_t<_In>> &&
   assignable_from<iter_value_t<_In>&, iter_rvalue_reference_t<_In>>;
 
+template<class _In, class _Out>
+concept indirectly_copyable =
+  indirectly_readable<_In> &&
+  indirectly_writable<_Out, iter_reference_t<_In>>;
+
+template<class _In, class _Out>
+concept indirectly_copyable_storable =
+  indirectly_copyable<_In, _Out> &&
+  indirectly_writable<_Out, iter_value_t<_In>&> &&
+  indirectly_writable<_Out, const iter_value_t<_In>&> &&
+  indirectly_writable<_Out, iter_value_t<_In>&&> &&
+  indirectly_writable<_Out, const iter_value_t<_In>&&> &&
+  copyable<iter_value_t<_In>> &&
+  constructible_from<iter_value_t<_In>, iter_reference_t<_In>> &&
+  assignable_from<iter_value_t<_In>&, iter_reference_t<_In>>;
+
 // Note: indirectly_swappable is located in iter_swap.h to prevent a dependency cycle
 // (both iter_swap and indirectly_swappable require indirectly_readable).
 

diff  --git a/libcxx/include/iterator b/libcxx/include/iterator
index cf92bb76fc24b..2b98db084cbc2 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -136,6 +136,13 @@ template<class In, class Out>
 template<class In, class Out>
   concept indirectly_movable_storable = see below;         // since C++20
 
+// [alg.req.ind.copy], concept indirectly_copyable
+template<class In, class Out>
+  concept indirectly_copyable = see below;                  // since C++20
+
+template<class In, class Out>
+  concept indirectly_copyable_storable = see below;         // since C++20
+
 // [alg.req.ind.swap], concept indirectly_swappable
 template<class I1, class I2 = I1>
   concept indirectly_swappable = see below;                // since C++20

diff  --git a/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
index 2ed52aa5e7f15..c9f1bbcbdb75b 100644
--- a/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/iterator_concept_conformance.compile.pass.cpp
@@ -34,6 +34,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert( std::indirectly_movable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<iterator, std::pair<int, int>*>);
+static_assert( std::indirectly_copyable<iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::bidirectional_iterator<const_iterator>);

diff  --git a/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
index 04bfa58062673..a79c214b546a5 100644
--- a/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multimap/iterator_concept_conformance.compile.pass.cpp
@@ -34,6 +34,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert( std::indirectly_movable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<iterator, std::pair<int, int>*>);
+static_assert( std::indirectly_copyable<iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::bidirectional_iterator<const_iterator>);

diff  --git a/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
index 746db070a6b27..d9f922d72693f 100644
--- a/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/multiset/iterator_concept_conformance.compile.pass.cpp
@@ -34,6 +34,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_movable<iterator, int*>);
 static_assert(std::indirectly_movable_storable<iterator, int*>);
+static_assert(std::indirectly_copyable<iterator, int*>);
+static_assert(std::indirectly_copyable_storable<iterator, int*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::bidirectional_iterator<const_iterator>);

diff  --git a/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
index 1c4028c0702fc..aa5c516e8066c 100644
--- a/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/iterator_concept_conformance.compile.pass.cpp
@@ -34,6 +34,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_movable<iterator, int*>);
 static_assert(std::indirectly_movable_storable<iterator, int*>);
+static_assert(std::indirectly_copyable<iterator, int*>);
+static_assert(std::indirectly_copyable_storable<iterator, int*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::bidirectional_iterator<const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
index badb8e63e754d..d0f62cdb9d2ea 100644
--- a/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/array/iterator_concept_conformance.compile.pass.cpp
@@ -38,6 +38,14 @@ static_assert( std::indirectly_movable<iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
 static_assert( std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::contiguous_iterator<const_iterator>);
@@ -58,4 +66,12 @@ static_assert( std::indirectly_movable<const_iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
index 7b5d7b14ab10e..3565f1796032d 100644
--- a/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/iterator_concept_conformance.compile.pass.cpp
@@ -40,6 +40,14 @@ static_assert( std::indirectly_movable<iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::random_access_iterator<const_iterator>);
@@ -61,4 +69,12 @@ static_assert( std::indirectly_movable<const_iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
index 69232d0e75b2f..a31a32b4a5818 100644
--- a/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/forwardlist/forwardlist.iter/iterator_concept_conformance.compile.pass.cpp
@@ -30,6 +30,10 @@ static_assert( std::indirectly_movable<iterator, iterator>);
 static_assert( std::indirectly_movable_storable<iterator, iterator>);
 static_assert(!std::indirectly_movable<iterator, const_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
 static_assert(std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
@@ -43,4 +47,8 @@ static_assert( std::indirectly_movable<const_iterator, iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
index 4356595340a84..2000ba85183f4 100644
--- a/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/list/iterator_concept_conformance.compile.pass.cpp
@@ -40,6 +40,14 @@ static_assert( std::indirectly_movable<iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::bidirectional_iterator<const_iterator>);
@@ -61,4 +69,12 @@ static_assert( std::indirectly_movable<const_iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
index fd7b6f4d064d8..933427895dbb7 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/iterator_concept_conformance.compile.pass.cpp
@@ -36,6 +36,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_movable<iterator, bool*>);
 static_assert(std::indirectly_movable_storable<iterator, bool*>);
+static_assert(std::indirectly_copyable<iterator, bool*>);
+static_assert(std::indirectly_copyable_storable<iterator, bool*>);
 static_assert(std::indirectly_swappable<iterator, iterator>);
 
 static_assert( std::random_access_iterator<const_iterator>);

diff  --git a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
index ea66d9ca429a8..856a2510e247c 100644
--- a/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/iterator_concept_conformance.compile.pass.cpp
@@ -41,6 +41,14 @@ static_assert( std::indirectly_movable<iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_swappable<iterator, iterator>);
 
 static_assert( std::contiguous_iterator<const_iterator>);
@@ -63,4 +71,12 @@ static_assert( std::indirectly_movable<const_iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
index e3e5d00bb4789..abdec3d41545d 100644
--- a/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.map/iterator_concept_conformance.compile.pass.cpp
@@ -32,6 +32,8 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(std::indirectly_movable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
@@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for<const_iterator, iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_iterator>);
 static_assert(std::indirectly_movable<const_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<const_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<const_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
@@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<local_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<local_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<local_iterator, local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
@@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for<const_local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<const_local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<const_local_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<const_local_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<const_local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<const_local_iterator, const_local_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
index 8fe699bbfbc48..2adc25a40c446 100644
--- a/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multimap/iterator_concept_conformance.compile.pass.cpp
@@ -32,6 +32,8 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(std::indirectly_movable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
@@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for<const_iterator, iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_iterator>);
 static_assert(std::indirectly_movable<const_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<const_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<const_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
@@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<local_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<local_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<local_iterator, local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
@@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for<const_local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<const_local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_movable_storable<const_local_iterator, std::pair<int, int>*>);
+static_assert(std::indirectly_copyable<const_local_iterator, std::pair<int, int>*>);
+static_assert(!std::indirectly_copyable_storable<const_local_iterator, std::pair<int, int>*>);
 static_assert(!std::indirectly_swappable<const_local_iterator, const_local_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
index 9c5612cafb0dd..bcafa404e008a 100644
--- a/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.multiset/iterator_concept_conformance.compile.pass.cpp
@@ -32,6 +32,8 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(std::indirectly_movable<iterator, int*>);
 static_assert(std::indirectly_movable_storable<iterator, int*>);
+static_assert(std::indirectly_copyable<iterator, int*>);
+static_assert(std::indirectly_copyable_storable<iterator, int*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
@@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for<const_iterator, iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_iterator>);
 static_assert(std::indirectly_movable<const_iterator, int*>);
 static_assert(std::indirectly_movable_storable<const_iterator, int*>);
+static_assert(std::indirectly_copyable<const_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<const_iterator, int*>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
@@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<local_iterator, int*>);
 static_assert(std::indirectly_movable_storable<local_iterator, int*>);
+static_assert(std::indirectly_copyable<local_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<local_iterator, int*>);
 static_assert(!std::indirectly_swappable<local_iterator, local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
@@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for<const_local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<const_local_iterator, int*>);
 static_assert(std::indirectly_movable_storable<const_local_iterator, int*>);
+static_assert(std::indirectly_copyable<const_local_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<const_local_iterator, int*>);
 static_assert(!std::indirectly_swappable<const_local_iterator, const_local_iterator>);

diff  --git a/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
index da7725768ea11..0a8d43f3a8804 100644
--- a/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/unord/unord.set/iterator_concept_conformance.compile.pass.cpp
@@ -32,6 +32,8 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_iterator>);
 static_assert(std::indirectly_movable<iterator, int*>);
 static_assert(std::indirectly_movable_storable<iterator, int*>);
+static_assert(std::indirectly_copyable<iterator, int*>);
+static_assert(std::indirectly_copyable_storable<iterator, int*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::forward_iterator<const_iterator>);
@@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for<const_iterator, iterator>);
 static_assert(!std::sized_sentinel_for<const_iterator, const_iterator>);
 static_assert(std::indirectly_movable<const_iterator, int*>);
 static_assert(std::indirectly_movable_storable<const_iterator, int*>);
+static_assert(std::indirectly_copyable<const_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<const_iterator, int*>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);
 
 static_assert(std::forward_iterator<local_iterator>);
@@ -53,6 +57,8 @@ static_assert(!std::sized_sentinel_for<local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<local_iterator, int*>);
 static_assert(std::indirectly_movable_storable<local_iterator, int*>);
+static_assert(std::indirectly_copyable<local_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<local_iterator, int*>);
 static_assert(!std::indirectly_swappable<local_iterator, local_iterator>);
 
 static_assert(std::forward_iterator<const_local_iterator>);
@@ -64,4 +70,6 @@ static_assert(!std::sized_sentinel_for<const_local_iterator, local_iterator>);
 static_assert(!std::sized_sentinel_for<const_local_iterator, const_local_iterator>);
 static_assert(std::indirectly_movable<const_local_iterator, int*>);
 static_assert(std::indirectly_movable_storable<const_local_iterator, int*>);
+static_assert(std::indirectly_copyable<const_local_iterator, int*>);
+static_assert(std::indirectly_copyable_storable<const_local_iterator, int*>);
 static_assert(!std::indirectly_swappable<const_local_iterator, const_local_iterator>);

diff  --git a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
index d994d3f411c75..a8839cb470ccb 100644
--- a/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/containers/views/span.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -29,4 +29,6 @@ static_assert(std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(std::indirectly_movable<iterator, int*>);
 static_assert(std::indirectly_movable_storable<iterator, int*>);
+static_assert(std::indirectly_copyable<iterator, int*>);
+static_assert(std::indirectly_copyable_storable<iterator, int*>);
 static_assert(std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/iterator_concept_conformance.compile.pass.cpp
index 45c2b98934445..c97bcef6d6207 100644
--- a/libcxx/test/std/input.output/filesystems/class.directory_iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/iterator_concept_conformance.compile.pass.cpp
@@ -25,6 +25,8 @@ static_assert(std::sentinel_for<fs::directory_iterator, fs::directory_iterator>)
 static_assert(!std::sized_sentinel_for<fs::directory_iterator, fs::directory_iterator>);
 static_assert(!std::indirectly_movable<fs::directory_iterator, fs::directory_iterator>);
 static_assert(!std::indirectly_movable_storable<fs::directory_iterator, fs::directory_iterator>);
+static_assert(!std::indirectly_copyable<fs::directory_iterator, fs::directory_iterator>);
+static_assert(!std::indirectly_copyable_storable<fs::directory_iterator, fs::directory_iterator>);
 static_assert(!std::indirectly_swappable<fs::directory_iterator, fs::directory_iterator>);
 
 static_assert(std::input_iterator<fs::recursive_directory_iterator>);
@@ -35,4 +37,6 @@ static_assert(std::sentinel_for<fs::recursive_directory_iterator, fs::recursive_
 static_assert(!std::sized_sentinel_for<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);
 static_assert(!std::indirectly_movable<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);
 static_assert(!std::indirectly_movable_storable<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);
+static_assert(!std::indirectly_copyable<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);
+static_assert(!std::indirectly_copyable_storable<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);
 static_assert(!std::indirectly_swappable<fs::recursive_directory_iterator, fs::recursive_directory_iterator>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.compile.pass.cpp
new file mode 100644
index 0000000000000..b71fb2c09d0f9
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.compile.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// template<class In, class Out>
+// concept indirectly_copyable;
+
+#include <iterator>
+
+#include "MoveOnly.h"
+#include "test_macros.h"
+
+struct CopyOnly {
+  CopyOnly() = default;
+
+  CopyOnly(CopyOnly const&) = default;
+  CopyOnly& operator=(CopyOnly const&) = default;
+
+  CopyOnly(CopyOnly&&) = delete;
+  CopyOnly& operator=(CopyOnly&&) = delete;
+};
+
+// Can copy the underlying objects between pointers.
+static_assert( std::indirectly_copyable<int*, int*>);
+static_assert( std::indirectly_copyable<const int*, int *>);
+
+// Can't copy if the output pointer is const.
+static_assert(!std::indirectly_copyable<int*, const int *>);
+static_assert(!std::indirectly_copyable<const int*, const int *>);
+
+// Can copy from a pointer into an array but arrays aren't considered indirectly copyable-from.
+static_assert( std::indirectly_copyable<int*, int[2]>);
+static_assert(!std::indirectly_copyable<int[2], int*>);
+static_assert(!std::indirectly_copyable<int[2], int[2]>);
+static_assert(!std::indirectly_copyable<int(&)[2], int(&)[2]>);
+
+// Can't copy between non-pointer types.
+static_assert(!std::indirectly_copyable<int*, int>);
+static_assert(!std::indirectly_copyable<int, int*>);
+static_assert(!std::indirectly_copyable<int, int>);
+
+// Check some less common types.
+static_assert(!std::indirectly_movable<void*, void*>);
+static_assert(!std::indirectly_movable<int*, void*>);
+static_assert(!std::indirectly_movable<int(), int()>);
+static_assert(!std::indirectly_movable<int*, int()>);
+static_assert(!std::indirectly_movable<void, void>);
+
+// Can't copy move-only objects.
+static_assert(!std::indirectly_copyable<MoveOnly*, MoveOnly*>);
+static_assert(!std::indirectly_copyable<MoveOnly*, const MoveOnly*>);
+static_assert(!std::indirectly_copyable<const MoveOnly*, MoveOnly*>);
+static_assert(!std::indirectly_copyable<const MoveOnly*, const MoveOnly*>);
+
+// Can copy copy-only objects.
+static_assert( std::indirectly_copyable<CopyOnly*, CopyOnly*>);
+static_assert(!std::indirectly_copyable<CopyOnly*, const CopyOnly*>);
+static_assert( std::indirectly_copyable<const CopyOnly*, CopyOnly*>);
+static_assert(!std::indirectly_copyable<const CopyOnly*, const CopyOnly*>);
+
+template<class T>
+struct PointerTo {
+  using value_type = T;
+  T& operator*() const;
+};
+
+// Can copy through a dereferenceable class.
+static_assert( std::indirectly_copyable<int*, PointerTo<int>>);
+static_assert(!std::indirectly_copyable<int*, PointerTo<const int>>);
+static_assert( std::indirectly_copyable<PointerTo<int>, PointerTo<int>>);
+static_assert(!std::indirectly_copyable<PointerTo<int>, PointerTo<const int>>);
+static_assert( std::indirectly_copyable<CopyOnly*, PointerTo<CopyOnly>>);
+static_assert( std::indirectly_copyable<PointerTo<CopyOnly>, CopyOnly*>);
+static_assert( std::indirectly_copyable<PointerTo<CopyOnly>, PointerTo<CopyOnly>>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.subsumption.compile.pass.cpp
new file mode 100644
index 0000000000000..ea681e5eb49dc
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.subsumption.compile.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// template<class In, class Out>
+// concept indirectly_copyable;
+
+#include <iterator>
+
+template<std::indirectly_readable I, class O>
+constexpr bool indirectly_copyable_subsumption() {
+  return false;
+}
+
+template<class I, class O>
+  requires std::indirectly_copyable<I, O>
+constexpr bool indirectly_copyable_subsumption() {
+  return true;
+}
+
+static_assert(indirectly_copyable_subsumption<int*, int*>());

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.compile.pass.cpp
new file mode 100644
index 0000000000000..faa15d4b1adeb
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.compile.pass.cpp
@@ -0,0 +1,305 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// template<class In, class Out>
+// concept indirectly_copyable_storable;
+
+#include <iterator>
+
+#include "MoveOnly.h"
+#include "test_macros.h"
+
+struct CopyOnly {
+  CopyOnly(CopyOnly&&) = delete;
+  CopyOnly(CopyOnly const&) = default;
+  CopyOnly& operator=(CopyOnly&&) = delete;
+  CopyOnly& operator=(CopyOnly const&) = default;
+  CopyOnly() = default;
+};
+
+template<class T>
+struct PointerTo {
+  using value_type = T;
+  T& operator*() const;
+};
+
+// Copying the underlying object between pointers (or dereferenceable classes) works. This is a non-exhaustive check
+// because this functionality comes from `indirectly_copyable`.
+static_assert( std::indirectly_copyable_storable<int*, int*>);
+static_assert( std::indirectly_copyable_storable<const int*, int*>);
+static_assert(!std::indirectly_copyable_storable<int*, const int*>);
+static_assert(!std::indirectly_copyable_storable<const int*, const int*>);
+static_assert( std::indirectly_copyable_storable<int*, int[2]>);
+static_assert(!std::indirectly_copyable_storable<int[2], int*>);
+static_assert(!std::indirectly_copyable_storable<MoveOnly*, MoveOnly*>);
+static_assert(!std::indirectly_copyable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);
+// `indirectly_copyable_storable` requires the type to be `copyable`, which in turns requires it to be `movable`.
+static_assert(!std::indirectly_copyable_storable<CopyOnly*, CopyOnly*>);
+static_assert(!std::indirectly_copyable_storable<PointerTo<CopyOnly>, PointerTo<CopyOnly>>);
+
+// The dereference operator returns a 
diff erent type from `value_type` and the reference type cannot be assigned from a
+// non-const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
+struct NoLvalueAssignment {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&);
+    ReferenceType& operator=(ValueType&) = delete;
+    ReferenceType& operator=(ValueType&&);
+    ReferenceType& operator=(ValueType const&&);
+  };
+
+  struct ValueType {
+    operator ReferenceType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_reference_t<NoLvalueAssignment>>);
+static_assert(!std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&&>);
+static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&&>);
+static_assert(!std::indirectly_copyable_storable<NoLvalueAssignment, NoLvalueAssignment>);
+
+// The dereference operator returns a 
diff erent type from `value_type` and the reference type cannot be assigned from a
+// const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
+struct NoConstLvalueAssignment {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&) = delete;
+    ReferenceType& operator=(ValueType&);
+    ReferenceType& operator=(ValueType&&);
+    ReferenceType& operator=(ValueType const&&);
+  };
+
+  struct ValueType {
+    operator ReferenceType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_reference_t<NoConstLvalueAssignment>>);
+static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&>);
+static_assert(!std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&&>);
+static_assert( std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&&>);
+static_assert(!std::indirectly_copyable_storable<NoConstLvalueAssignment, NoConstLvalueAssignment>);
+
+// The dereference operator returns a 
diff erent type from `value_type` and the reference type cannot be assigned from a
+// non-const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
+struct NoRvalueAssignment {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&);
+    ReferenceType& operator=(ValueType&);
+    ReferenceType& operator=(ValueType&&) = delete;
+    ReferenceType& operator=(ValueType const&&);
+  };
+
+  struct ValueType {
+    operator ReferenceType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_reference_t<NoRvalueAssignment>>);
+static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&>);
+static_assert(!std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&&>);
+static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&&>);
+static_assert(!std::indirectly_copyable_storable<NoRvalueAssignment, NoRvalueAssignment>);
+
+// The dereference operator returns a 
diff erent type from `value_type` and the reference type cannot be assigned from a
+// const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work).
+struct NoConstRvalueAssignment {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&);
+    ReferenceType& operator=(ValueType&);
+    ReferenceType& operator=(ValueType&&);
+    ReferenceType& operator=(ValueType const&&) = delete;
+  };
+
+  struct ValueType {
+    operator ReferenceType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_reference_t<NoConstRvalueAssignment>>);
+static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&>);
+static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&&>);
+static_assert(!std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&&>);
+static_assert(!std::indirectly_copyable_storable<NoConstRvalueAssignment, NoConstRvalueAssignment>);
+
+struct DeletedCopyCtor {
+  DeletedCopyCtor(DeletedCopyCtor const&) = delete;
+  DeletedCopyCtor& operator=(DeletedCopyCtor const&) = default;
+};
+
+struct DeletedNonconstCopyCtor {
+  DeletedNonconstCopyCtor(DeletedNonconstCopyCtor const&) = default;
+  DeletedNonconstCopyCtor(DeletedNonconstCopyCtor&) = delete;
+  DeletedNonconstCopyCtor& operator=(DeletedNonconstCopyCtor const&) = default;
+};
+
+struct DeletedMoveCtor {
+  DeletedMoveCtor(DeletedMoveCtor&&) = delete;
+  DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default;
+};
+
+struct DeletedConstMoveCtor {
+  DeletedConstMoveCtor(DeletedConstMoveCtor&&) = default;
+  DeletedConstMoveCtor(DeletedConstMoveCtor const&&) = delete;
+  DeletedConstMoveCtor& operator=(DeletedConstMoveCtor&&) = default;
+};
+
+struct DeletedCopyAssignment {
+  DeletedCopyAssignment(DeletedCopyAssignment const&) = default;
+  DeletedCopyAssignment& operator=(DeletedCopyAssignment const&) = delete;
+};
+
+struct DeletedNonconstCopyAssignment {
+  DeletedNonconstCopyAssignment(DeletedNonconstCopyAssignment const&) = default;
+  DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment const&) = default;
+  DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment&) = delete;
+};
+
+struct DeletedMoveAssignment {
+  DeletedMoveAssignment(DeletedMoveAssignment&&) = default;
+  DeletedMoveAssignment& operator=(DeletedMoveAssignment&&) = delete;
+};
+
+struct DeletedConstMoveAssignment {
+  DeletedConstMoveAssignment(DeletedConstMoveAssignment&&) = default;
+  DeletedConstMoveAssignment& operator=(DeletedConstMoveAssignment&&) = delete;
+};
+
+static_assert(!std::indirectly_copyable_storable<DeletedCopyCtor*, DeletedCopyCtor*>);
+static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyCtor*, DeletedNonconstCopyCtor*>);
+static_assert(!std::indirectly_copyable_storable<DeletedMoveCtor*, DeletedMoveCtor*>);
+static_assert(!std::indirectly_copyable_storable<DeletedConstMoveCtor*, DeletedConstMoveCtor*>);
+static_assert(!std::indirectly_copyable_storable<DeletedCopyAssignment*, DeletedCopyAssignment*>);
+static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyAssignment*, DeletedNonconstCopyAssignment*>);
+static_assert(!std::indirectly_copyable_storable<DeletedMoveAssignment*, DeletedMoveAssignment*>);
+static_assert(!std::indirectly_copyable_storable<DeletedConstMoveAssignment*, DeletedConstMoveAssignment*>);
+
+struct InconsistentIterator {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&);
+  };
+
+  struct ValueType {
+    ValueType() = default;
+    ValueType(const ReferenceType&);
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+// `ValueType` can be constructed with a `ReferenceType` and assigned to a `ReferenceType`, so it does model
+// `indirectly_copyable_storable`.
+static_assert( std::indirectly_copyable_storable<InconsistentIterator, InconsistentIterator>);
+
+struct CommonType { };
+
+// ReferenceType is a (proxy) reference for ValueType, but ValueType is not constructible from ReferenceType.
+struct NotConstructibleFromRefIn {
+  struct ReferenceType;
+
+  struct ValueType {
+    ValueType(ReferenceType) = delete;
+    operator CommonType&() const;
+  };
+
+  struct ReferenceType {
+    operator CommonType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+template <template <class> class X, template <class> class Y>
+struct std::basic_common_reference<NotConstructibleFromRefIn::ValueType,
+                                   NotConstructibleFromRefIn::ReferenceType, X, Y> {
+  using type = CommonType&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct std::basic_common_reference<NotConstructibleFromRefIn::ReferenceType,
+                                   NotConstructibleFromRefIn::ValueType, X, Y> {
+  using type = CommonType&;
+};
+
+static_assert(std::common_reference_with<NotConstructibleFromRefIn::ValueType&,
+    NotConstructibleFromRefIn::ReferenceType&>);
+
+struct AssignableFromAnything {
+  template<class T>
+  AssignableFromAnything& operator=(T&&);
+};
+
+// A type that can't be constructed from its own reference isn't `indirectly_copyable_storable`, even when assigning it
+// to a type that can be assigned from anything.
+static_assert(!std::indirectly_copyable_storable<NotConstructibleFromRefIn, AssignableFromAnything*>);
+
+// ReferenceType is a (proxy) reference for ValueType, but ValueType is not assignable from ReferenceType.
+struct NotAssignableFromRefIn {
+  struct ReferenceType;
+
+  struct ValueType {
+    ValueType(ReferenceType);
+    ValueType& operator=(ReferenceType) = delete;
+    operator CommonType&() const;
+  };
+
+  struct ReferenceType {
+    operator CommonType&() const;
+  };
+
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+template <template <class> class X, template <class> class Y>
+struct std::basic_common_reference<NotAssignableFromRefIn::ValueType,
+                                   NotAssignableFromRefIn::ReferenceType, X, Y> {
+  using type = CommonType&;
+};
+
+template <template <class> class X, template <class> class Y>
+struct std::basic_common_reference<NotAssignableFromRefIn::ReferenceType,
+                                   NotAssignableFromRefIn::ValueType, X, Y> {
+  using type = CommonType&;
+};
+
+static_assert(std::common_reference_with<NotAssignableFromRefIn::ValueType&, NotAssignableFromRefIn::ReferenceType&>);
+
+// A type that can't be assigned from its own reference isn't `indirectly_copyable_storable`, even when assigning it
+// to a type that can be assigned from anything.
+static_assert(!std::indirectly_copyable_storable<NotAssignableFromRefIn, AssignableFromAnything*>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.subsumption.compile.pass.cpp
new file mode 100644
index 0000000000000..6c74bda226d1b
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable_storable.subsumption.compile.pass.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// template<class In, class Out>
+// concept indirectly_copyable_storable;
+
+#include <iterator>
+
+template<class I, class O>
+  requires std::indirectly_copyable<I, O>
+constexpr bool indirectly_copyable_storable_subsumption() {
+  return false;
+}
+
+template<class I, class O>
+  requires std::indirectly_copyable_storable<I, O>
+constexpr bool indirectly_copyable_storable_subsumption() {
+  return true;
+}
+
+static_assert(indirectly_copyable_storable_subsumption<int*, int*>());

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.compile.pass.cpp
index 743e0257313cb..118edc505655a 100644
--- a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.compile.pass.cpp
@@ -14,45 +14,50 @@
 
 #include <iterator>
 
+#include "MoveOnly.h"
 #include "test_macros.h"
 
-struct IndirectlyMovableWithInt {
-  int& operator*() const;
-};
-
-struct Empty {};
-
-struct MoveOnly {
-  MoveOnly(MoveOnly&&) = default;
-  MoveOnly(MoveOnly const&) = delete;
-  MoveOnly& operator=(MoveOnly&&) = default;
-  MoveOnly& operator=(MoveOnly const&) = delete;
-  MoveOnly() = default;
-};
-
-template<class T>
-struct PointerTo {
-  using value_type = T;
-  T& operator*() const;
-};
-
+// Can move between pointers.
 static_assert( std::indirectly_movable<int*, int*>);
-static_assert( std::indirectly_movable<const int*, int *>);
-static_assert(!std::indirectly_movable<int*, const int *>);
-static_assert(!std::indirectly_movable<const int*, const int *>);
+static_assert( std::indirectly_movable<const int*, int*>);
+static_assert(!std::indirectly_movable<int*, const int*>);
+static_assert( std::indirectly_movable<const int*, int*>);
+
+// Can move from a pointer into an array but arrays aren't considered indirectly movable-from.
 static_assert( std::indirectly_movable<int*, int[2]>);
 static_assert(!std::indirectly_movable<int[2], int*>);
 static_assert(!std::indirectly_movable<int[2], int[2]>);
 static_assert(!std::indirectly_movable<int(&)[2], int(&)[2]>);
+
+// Can't move between non-pointer types.
+static_assert(!std::indirectly_movable<int*, int>);
 static_assert(!std::indirectly_movable<int, int*>);
 static_assert(!std::indirectly_movable<int, int>);
-static_assert( std::indirectly_movable<Empty*, Empty*>);
-static_assert( std::indirectly_movable<int*, IndirectlyMovableWithInt>);
-static_assert(!std::indirectly_movable<Empty*, IndirectlyMovableWithInt>);
-static_assert( std::indirectly_movable<int*, IndirectlyMovableWithInt>);
+
+// Check some less common types.
+static_assert(!std::indirectly_movable<void*, void*>);
+static_assert(!std::indirectly_movable<int*, void*>);
+static_assert(!std::indirectly_movable<int(), int()>);
+static_assert(!std::indirectly_movable<int*, int()>);
+static_assert(!std::indirectly_movable<void, void>);
+
+// Can move move-only objects.
 static_assert( std::indirectly_movable<MoveOnly*, MoveOnly*>);
 static_assert(!std::indirectly_movable<MoveOnly*, const MoveOnly*>);
 static_assert(!std::indirectly_movable<const MoveOnly*, const MoveOnly*>);
 static_assert(!std::indirectly_movable<const MoveOnly*, MoveOnly*>);
-static_assert( std::indirectly_movable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);
+
+template<class T>
+struct PointerTo {
+  using value_type = T;
+  T& operator*() const;
+};
+
+// Can copy through a dereferenceable class.
+static_assert( std::indirectly_movable<int*, PointerTo<int>>);
+static_assert(!std::indirectly_movable<int*, PointerTo<const int>>);
+static_assert( std::indirectly_copyable<PointerTo<int>, PointerTo<int>>);
+static_assert(!std::indirectly_copyable<PointerTo<int>, PointerTo<const int>>);
 static_assert( std::indirectly_movable<MoveOnly*, PointerTo<MoveOnly>>);
+static_assert( std::indirectly_movable<PointerTo<MoveOnly>, MoveOnly*>);
+static_assert( std::indirectly_movable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp
index c101040b68992..a31753acdf916 100644
--- a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp
@@ -14,8 +14,6 @@
 
 #include <iterator>
 
-#include <concepts>
-
 template<std::indirectly_readable I, class O>
 constexpr bool indirectly_movable_subsumption() {
   return false;

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.compile.pass.cpp
index e6737c5886ee1..7bba23099fceb 100644
--- a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.compile.pass.cpp
@@ -14,59 +14,97 @@
 
 #include <iterator>
 
+#include "MoveOnly.h"
 #include "test_macros.h"
 
-struct Empty {};
+template <class T>
+struct PointerTo {
+  using value_type = T;
+  T& operator*() const;
+};
 
-struct MoveOnlyConvertible;
-struct AssignableToMoveOnly;
+// Copying the underlying object between pointers (or dereferenceable classes) works. This is a non-exhaustive check
+// because this functionality comes from `indirectly_movable`.
+static_assert( std::indirectly_movable_storable<int*, int*>);
+static_assert( std::indirectly_movable_storable<const int*, int*>);
+static_assert(!std::indirectly_movable_storable<int*, const int*>);
+static_assert(!std::indirectly_movable_storable<const int*, const int*>);
+static_assert( std::indirectly_movable_storable<int*, int[2]>);
+static_assert(!std::indirectly_movable_storable<int[2], int*>);
+static_assert( std::indirectly_movable_storable<MoveOnly*, MoveOnly*>);
+static_assert( std::indirectly_movable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);
 
-struct MoveOnly {
-  MoveOnly(MoveOnly&&) = default;
-  MoveOnly(MoveOnly const&) = delete;
-  MoveOnly& operator=(MoveOnly&&) = default;
-  MoveOnly& operator=(MoveOnly const&) = delete;
-  MoveOnly() = default;
+// The dereference operator returns a 
diff erent type from `value_type` and the reference type cannot be assigned from a
+// `ValueType`.
+struct NoAssignment {
+  struct ValueType;
 
-  MoveOnly& operator=(MoveOnlyConvertible const&) = delete;
-  MoveOnly& operator=(AssignableToMoveOnly const&);
-};
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType) = delete;
+  };
 
-template<class T, class ValueType = T>
-struct PointerTo {
-  using value_type = ValueType;
-  T& operator*() const;
-};
+  // `ValueType` is convertible to `ReferenceType` but not assignable to it. This is implemented by explicitly deleting
+  // `operator=(ValueType)` in `ReferenceType`.
+  struct ValueType {
+    operator ReferenceType&() const;
+  };
 
-// MoveOnlyConvertible is convertible to MoveOnly, but not assignable to it. This is
-// implemented by explicitly deleting "operator=(MoveOnlyConvertible)" in MoveOnly.
-struct MoveOnlyConvertible {
-  operator MoveOnly&() const;
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
 };
 
-// This type can be constructed with a MoveOnly and assigned to a MoveOnly, so it does
-// model indirectly_movable_storable.
-struct AssignableToMoveOnly {
-  AssignableToMoveOnly() = default;
-  AssignableToMoveOnly(const MoveOnly&);
-};
+// The case when `indirectly_writable<iter_rvalue_reference>` but not `indirectly_writable<iter_value>` (you can
+// do `ReferenceType r = ValueType();` but not `r = ValueType();`).
+static_assert( std::indirectly_writable<NoAssignment, std::iter_rvalue_reference_t<NoAssignment>>);
+static_assert(!std::indirectly_writable<NoAssignment, std::iter_value_t<NoAssignment>>);
+static_assert(!std::indirectly_movable_storable<NoAssignment, NoAssignment>);
 
 struct DeletedMoveCtor {
   DeletedMoveCtor(DeletedMoveCtor&&) = delete;
   DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default;
 };
 
-struct CommonType { };
+struct DeletedMoveAssignment {
+  DeletedMoveAssignment(DeletedMoveAssignment&&) = default;
+  DeletedMoveAssignment& operator=(DeletedMoveAssignment&&) = delete;
+};
+
+static_assert(!std::indirectly_movable_storable<DeletedMoveCtor*, DeletedMoveCtor*>);
+static_assert(!std::indirectly_movable_storable<DeletedMoveAssignment*, DeletedMoveAssignment*>);
+
+struct InconsistentIterator {
+  struct ValueType;
+
+  struct ReferenceType {
+    ReferenceType& operator=(ValueType const&);
+  };
 
-struct NotConstructibleFromRefIn {
   struct ValueType {
-    operator CommonType&() const;
+    ValueType() = default;
+    ValueType(const ReferenceType&);
   };
 
+  using value_type = ValueType;
+  ReferenceType& operator*() const;
+};
+
+// `ValueType` can be constructed with a `ReferenceType` and assigned to a `ReferenceType`, so it does model
+// `indirectly_movable_storable`.
+static_assert( std::indirectly_movable_storable<InconsistentIterator, InconsistentIterator>);
+
+// ReferenceType is a (proxy) reference for ValueType, but ValueType is not constructible from ReferenceType.
+struct NotConstructibleFromRefIn {
+  struct CommonType { };
+
   struct ReferenceType {
     operator CommonType&() const;
   };
 
+  struct ValueType {
+    ValueType(ReferenceType) = delete;
+    operator CommonType&() const;
+  };
+
   using value_type = ValueType;
   ReferenceType& operator*() const;
 };
@@ -74,25 +112,39 @@ struct NotConstructibleFromRefIn {
 template <template <class> class X, template <class> class Y>
 struct std::basic_common_reference<NotConstructibleFromRefIn::ValueType,
                                    NotConstructibleFromRefIn::ReferenceType, X, Y> {
-  using type = CommonType&;
+  using type = NotConstructibleFromRefIn::CommonType&;
 };
 
 template <template <class> class X, template <class> class Y>
 struct std::basic_common_reference<NotConstructibleFromRefIn::ReferenceType,
                                    NotConstructibleFromRefIn::ValueType, X, Y> {
-  using type = CommonType&;
+  using type = NotConstructibleFromRefIn::CommonType&;
 };
 
+static_assert(std::common_reference_with<NotConstructibleFromRefIn::ValueType&,
+    NotConstructibleFromRefIn::ReferenceType&>);
+
+struct AssignableFromAnything {
+  template<class T>
+  AssignableFromAnything& operator=(T&&);
+};
+
+// A type that can't be constructed from its own reference isn't `indirectly_movable_storable`, even when assigning it
+// to a type that can be assigned from anything.
+static_assert( std::indirectly_movable_storable<int*, AssignableFromAnything*>);
+static_assert(!std::indirectly_movable_storable<NotConstructibleFromRefIn, AssignableFromAnything*>);
+
+// ReferenceType is a (proxy) reference for ValueType, but ValueType is not assignable from ReferenceType.
 struct NotAssignableFromRefIn {
-  struct ReferenceType;
+  struct CommonType { };
 
-  struct ValueType {
-    ValueType(ReferenceType);
-    ValueType& operator=(ReferenceType) = delete;
+  struct ReferenceType {
     operator CommonType&() const;
   };
 
-  struct ReferenceType {
+  struct ValueType {
+    ValueType(ReferenceType);
+    ValueType& operator=(ReferenceType) = delete;
     operator CommonType&() const;
   };
 
@@ -103,40 +155,17 @@ struct NotAssignableFromRefIn {
 template <template <class> class X, template <class> class Y>
 struct std::basic_common_reference<NotAssignableFromRefIn::ValueType,
                                    NotAssignableFromRefIn::ReferenceType, X, Y> {
-  using type = CommonType&;
+  using type = NotAssignableFromRefIn::CommonType&;
 };
 
 template <template <class> class X, template <class> class Y>
 struct std::basic_common_reference<NotAssignableFromRefIn::ReferenceType,
                                    NotAssignableFromRefIn::ValueType, X, Y> {
-  using type = CommonType&;
+  using type = NotAssignableFromRefIn::CommonType&;
 };
 
-struct AnyWritable {
-  template<class T>
-  AnyWritable& operator=(T&&);
-};
+static_assert(std::common_reference_with<NotAssignableFromRefIn::ValueType&, NotAssignableFromRefIn::ReferenceType&>);
 
-struct AnyOutput {
-  using value_type = AnyWritable;
-  AnyWritable& operator*() const;
-};
-
-static_assert( std::indirectly_movable_storable<int*, int*>);
-static_assert( std::indirectly_movable_storable<const int*, int *>);
-static_assert( std::indirectly_movable_storable<int*, int[2]>);
-static_assert( std::indirectly_movable_storable<Empty*, Empty*>);
-static_assert( std::indirectly_movable_storable<MoveOnly*, MoveOnly*>);
-static_assert( std::indirectly_movable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>);
-// The case when indirectly_writable<iter_rvalue_reference> but not indirectly_writable<iter_value>.
-static_assert( std::indirectly_writable<
-                 PointerTo<MoveOnly, MoveOnlyConvertible>,
-                 std::iter_rvalue_reference_t<
-                    PointerTo<MoveOnly, MoveOnlyConvertible>>>);
-static_assert(!std::indirectly_movable_storable<PointerTo<MoveOnly, MoveOnlyConvertible>,
-                                                PointerTo<MoveOnly, MoveOnlyConvertible>>);
-static_assert(!std::indirectly_movable_storable<DeletedMoveCtor*, DeletedMoveCtor*>);
-static_assert( std::indirectly_movable_storable<PointerTo<MoveOnly, AssignableToMoveOnly>,
-                                                PointerTo<MoveOnly, AssignableToMoveOnly>>);
-static_assert(!std::indirectly_movable_storable<NotConstructibleFromRefIn, AnyOutput>);
-static_assert(!std::indirectly_movable_storable<NotAssignableFromRefIn, AnyOutput>);
+// A type that can't be assigned from its own reference isn't `indirectly_movable_storable`, even when assigning it
+// to a type that can be assigned from anything.
+static_assert(!std::indirectly_movable_storable<NotAssignableFromRefIn, AssignableFromAnything*>);

diff  --git a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.subsumption.compile.pass.cpp
index 4858b8890e63c..a04581eadb597 100644
--- a/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.subsumption.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable_storable.subsumption.compile.pass.cpp
@@ -14,8 +14,6 @@
 
 #include <iterator>
 
-#include <concepts>
-
 template<class I, class O>
   requires std::indirectly_movable<I, O>
 constexpr bool indirectly_movable_storable_subsumption() {

diff  --git a/libcxx/test/std/iterators/predef.iterators/insert.iterators/back.insert.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/insert.iterators/back.insert.iterator/iterator_concept_conformance.compile.pass.cpp
index 3a00358800679..5fe089d95aefd 100644
--- a/libcxx/test/std/iterators/predef.iterators/insert.iterators/back.insert.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/insert.iterators/back.insert.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -25,4 +25,6 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::input_iterator<iterator>);
 static_assert(std::indirectly_movable<int*, iterator>);
 static_assert(std::indirectly_movable_storable<int*, iterator>);
+static_assert(std::indirectly_copyable<int*, iterator>);
+static_assert(std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/insert.iterators/front.insert.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/insert.iterators/front.insert.iterator/iterator_concept_conformance.compile.pass.cpp
index 22786e79a3d45..996aa1cdf289c 100644
--- a/libcxx/test/std/iterators/predef.iterators/insert.iterators/front.insert.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/insert.iterators/front.insert.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -25,4 +25,6 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::input_iterator<iterator>);
 static_assert(std::indirectly_movable<int*, iterator>);
 static_assert(std::indirectly_movable_storable<int*, iterator>);
+static_assert(std::indirectly_copyable<int*, iterator>);
+static_assert(std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/iterator_concept_conformance.compile.pass.cpp
index 9e8392976a9bb..ac2d1a523aa38 100644
--- a/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/insert.iterators/insert.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -24,4 +24,6 @@ static_assert(!std::sentinel_for<iterator, iterator>);
 static_assert(!std::input_iterator<iterator>);
 static_assert(std::indirectly_movable<int*, iterator>);
 static_assert(std::indirectly_movable_storable<int*, iterator>);
+static_assert(std::indirectly_copyable<int*, iterator>);
+static_assert(std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp
index 9f18bcf0467e4..2fdadff1afc9f 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -23,4 +23,6 @@ static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::indirectly_movable<int*, iterator>);
 static_assert(!std::indirectly_movable_storable<int*, iterator>);
+static_assert(!std::indirectly_copyable<int*, iterator>);
+static_assert(!std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
index 0b26a3324e71e..063330c930f40 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -31,6 +31,8 @@ static_assert(!std::random_access_iterator<reverse_bidirectional_iterator>);
 static_assert(!std::sized_sentinel_for<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
 static_assert( std::indirectly_movable<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
 static_assert( std::indirectly_movable_storable<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
+static_assert( std::indirectly_copyable<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
+static_assert( std::indirectly_copyable_storable<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
 static_assert( std::indirectly_swappable<reverse_bidirectional_iterator, reverse_bidirectional_iterator>);
 
 using reverse_random_access_iterator = std::reverse_iterator<random_access_iterator<int*>>;
@@ -40,6 +42,8 @@ static_assert(!std::contiguous_iterator<reverse_random_access_iterator>);
 static_assert(std::sized_sentinel_for<reverse_random_access_iterator, reverse_random_access_iterator>);
 static_assert( std::indirectly_movable<reverse_random_access_iterator, reverse_random_access_iterator>);
 static_assert( std::indirectly_movable_storable<reverse_random_access_iterator, reverse_random_access_iterator>);
+static_assert( std::indirectly_copyable<reverse_random_access_iterator, reverse_random_access_iterator>);
+static_assert( std::indirectly_copyable_storable<reverse_random_access_iterator, reverse_random_access_iterator>);
 static_assert( std::indirectly_swappable<reverse_random_access_iterator, reverse_random_access_iterator>);
 
 using reverse_contiguous_iterator = std::reverse_iterator<contiguous_iterator<int*>>;
@@ -49,4 +53,6 @@ static_assert(!std::contiguous_iterator<reverse_contiguous_iterator>);
 static_assert(std::sized_sentinel_for<reverse_contiguous_iterator, reverse_contiguous_iterator>);
 static_assert( std::indirectly_movable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
 static_assert( std::indirectly_movable_storable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
+static_assert( std::indirectly_copyable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
+static_assert( std::indirectly_copyable_storable<reverse_contiguous_iterator, reverse_contiguous_iterator>);
 static_assert( std::indirectly_swappable<reverse_contiguous_iterator, reverse_contiguous_iterator>);

diff  --git a/libcxx/test/std/iterators/stream.iterators/istream.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istream.iterator/iterator_concept_conformance.compile.pass.cpp
index 120cc497277bc..1a87c0fc820d8 100644
--- a/libcxx/test/std/iterators/stream.iterators/istream.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/stream.iterators/istream.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -25,4 +25,6 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(std::input_iterator<iterator>);
 static_assert(!std::indirectly_movable<int*, iterator>);
 static_assert(!std::indirectly_movable_storable<int*, iterator>);
+static_assert(!std::indirectly_copyable<int*, iterator>);
+static_assert(!std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
index 831bc4541c96c..226e3009fc23c 100644
--- a/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/stream.iterators/istreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -26,4 +26,6 @@ static_assert(std::sentinel_for<iterator, iterator>);
 static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(std::indirectly_movable<iterator, char*>);
 static_assert(std::indirectly_movable_storable<iterator, char*>);
+static_assert(std::indirectly_copyable<iterator, char*>);
+static_assert(std::indirectly_copyable_storable<iterator, char*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/stream.iterators/ostream.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/stream.iterators/ostream.iterator/iterator_concept_conformance.compile.pass.cpp
index cbcecdaf24fa2..580305fd386a6 100644
--- a/libcxx/test/std/iterators/stream.iterators/ostream.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/stream.iterators/ostream.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -25,4 +25,6 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::input_iterator<iterator>);
 static_assert(std::indirectly_movable<int*, iterator>);
 static_assert(std::indirectly_movable_storable<int*, iterator>);
+static_assert(std::indirectly_copyable<int*, iterator>);
+static_assert(std::indirectly_copyable_storable<int*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/iterators/stream.iterators/ostreambuf.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/stream.iterators/ostreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
index 66d79722b8ec1..cf709515f5f74 100644
--- a/libcxx/test/std/iterators/stream.iterators/ostreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/iterators/stream.iterators/ostreambuf.iterator/iterator_concept_conformance.compile.pass.cpp
@@ -26,4 +26,6 @@ static_assert(!std::sized_sentinel_for<iterator, iterator>);
 static_assert(!std::input_iterator<iterator>);
 static_assert(std::indirectly_movable<char*, iterator>);
 static_assert(std::indirectly_movable_storable<char*, iterator>);
+static_assert(std::indirectly_copyable<char*, iterator>);
+static_assert(std::indirectly_copyable_storable<char*, iterator>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);

diff  --git a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
index ca93e24546528..b9c8237d593e7 100644
--- a/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp
@@ -22,4 +22,6 @@ static_assert(std::sentinel_for<std::cregex_iterator, std::cregex_iterator>);
 static_assert(!std::sized_sentinel_for<std::cregex_iterator, std::cregex_iterator>);
 static_assert(!std::indirectly_movable<std::cregex_iterator, std::cregex_iterator>);
 static_assert(!std::indirectly_movable_storable<std::cregex_iterator, std::cregex_iterator>);
+static_assert(!std::indirectly_copyable<std::cregex_iterator, std::cregex_iterator>);
+static_assert(!std::indirectly_copyable_storable<std::cregex_iterator, std::cregex_iterator>);
 static_assert(!std::indirectly_swappable<std::cregex_iterator, std::cregex_iterator>);

diff  --git a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
index 5e0b906b775c5..ad4066f2389a9 100644
--- a/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp
@@ -22,4 +22,6 @@ static_assert(std::sentinel_for<std::cregex_token_iterator, std::cregex_token_it
 static_assert(!std::sized_sentinel_for<std::cregex_token_iterator, std::cregex_token_iterator>);
 static_assert(!std::indirectly_movable<std::cregex_token_iterator, std::cregex_token_iterator>);
 static_assert(!std::indirectly_movable_storable<std::cregex_token_iterator, std::cregex_token_iterator>);
+static_assert(!std::indirectly_copyable<std::cregex_token_iterator, std::cregex_token_iterator>);
+static_assert(!std::indirectly_copyable_storable<std::cregex_token_iterator, std::cregex_token_iterator>);
 static_assert(!std::indirectly_swappable<std::cregex_token_iterator, std::cregex_token_iterator>);

diff  --git a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
index 5bd2f769fb936..255d5c464960d 100644
--- a/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -39,6 +39,14 @@ static_assert( std::indirectly_movable<iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_iterator>);
+static_assert( std::indirectly_copyable<iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<iterator, const_reverse_iterator>);
 static_assert( std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::contiguous_iterator<const_iterator>);
@@ -59,4 +67,12 @@ static_assert( std::indirectly_movable<const_iterator, reverse_iterator>);
 static_assert( std::indirectly_movable_storable<const_iterator, reverse_iterator>);
 static_assert(!std::indirectly_movable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_movable_storable<const_iterator, const_reverse_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_iterator>);
+static_assert( std::indirectly_copyable<const_iterator, reverse_iterator>);
+static_assert( std::indirectly_copyable_storable<const_iterator, reverse_iterator>);
+static_assert(!std::indirectly_copyable<const_iterator, const_reverse_iterator>);
+static_assert(!std::indirectly_copyable_storable<const_iterator, const_reverse_iterator>);
 static_assert(!std::indirectly_swappable<const_iterator, const_iterator>);

diff  --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
index 711bfd6fa6485..7277e62973b2a 100644
--- a/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterator_concept_conformance.compile.pass.cpp
@@ -35,6 +35,8 @@ static_assert(!std::sized_sentinel_for<iterator, reverse_iterator>);
 static_assert(!std::sized_sentinel_for<iterator, const_reverse_iterator>);
 static_assert(std::indirectly_movable<iterator, char*>);
 static_assert(std::indirectly_movable_storable<iterator, char*>);
+static_assert(std::indirectly_copyable<iterator, char*>);
+static_assert(std::indirectly_copyable_storable<iterator, char*>);
 static_assert(!std::indirectly_swappable<iterator, iterator>);
 
 static_assert(std::contiguous_iterator<const_iterator>);

diff  --git a/libcxx/test/std/utilities/memory/unique.ptr/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/utilities/memory/unique.ptr/iterator_concept_conformance.compile.pass.cpp
index 1fc30171eb42d..9e384fe38dea6 100644
--- a/libcxx/test/std/utilities/memory/unique.ptr/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/utilities/memory/unique.ptr/iterator_concept_conformance.compile.pass.cpp
@@ -20,6 +20,8 @@ static_assert(std::indirectly_writable<std::unique_ptr<int>, int>);
 static_assert(!std::weakly_incrementable<std::unique_ptr<int> >);
 static_assert(std::indirectly_movable<std::unique_ptr<int>, std::unique_ptr<int>>);
 static_assert(std::indirectly_movable_storable<std::unique_ptr<int>, std::unique_ptr<int>>);
+static_assert(std::indirectly_copyable<std::unique_ptr<int>, std::unique_ptr<int>>);
+static_assert(std::indirectly_copyable_storable<std::unique_ptr<int>, std::unique_ptr<int>>);
 static_assert(std::indirectly_swappable<std::unique_ptr<int>, std::unique_ptr<int> >);
 
 static_assert(!std::indirectly_readable<std::unique_ptr<void> >);
@@ -27,3 +29,5 @@ static_assert(!std::indirectly_writable<std::unique_ptr<void>, void>);
 static_assert(!std::weakly_incrementable<std::unique_ptr<void> >);
 static_assert(!std::indirectly_movable<std::unique_ptr<void>, std::unique_ptr<void>>);
 static_assert(!std::indirectly_movable_storable<std::unique_ptr<void>, std::unique_ptr<void>>);
+static_assert(!std::indirectly_copyable<std::unique_ptr<void>, std::unique_ptr<void>>);
+static_assert(!std::indirectly_copyable_storable<std::unique_ptr<void>, std::unique_ptr<void>>);

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/iterator_concept_conformance.compile.pass.cpp
index a89cb3ee247b2..8851aedc04cdc 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/iterator_concept_conformance.compile.pass.cpp
@@ -20,6 +20,8 @@ static_assert(std::indirectly_writable<std::shared_ptr<int>, int>);
 static_assert(!std::weakly_incrementable<std::shared_ptr<int> >);
 static_assert(std::indirectly_movable<std::shared_ptr<int>, std::shared_ptr<int>>);
 static_assert(std::indirectly_movable_storable<std::shared_ptr<int>, std::shared_ptr<int>>);
+static_assert(std::indirectly_copyable<std::shared_ptr<int>, std::shared_ptr<int>>);
+static_assert(std::indirectly_copyable_storable<std::shared_ptr<int>, std::shared_ptr<int>>);
 static_assert(std::indirectly_swappable<std::shared_ptr<int>, std::shared_ptr<int> >);
 
 static_assert(!std::indirectly_readable<std::shared_ptr<void> >);
@@ -27,3 +29,5 @@ static_assert(!std::indirectly_writable<std::shared_ptr<void>, void>);
 static_assert(!std::weakly_incrementable<std::shared_ptr<void> >);
 static_assert(!std::indirectly_movable<std::shared_ptr<void>, std::shared_ptr<void>>);
 static_assert(!std::indirectly_movable_storable<std::shared_ptr<void>, std::shared_ptr<void>>);
+static_assert(!std::indirectly_copyable<std::shared_ptr<void>, std::shared_ptr<void>>);
+static_assert(!std::indirectly_copyable_storable<std::shared_ptr<void>, std::shared_ptr<void>>);

diff  --git a/libcxx/test/std/utilities/optional/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/utilities/optional/iterator_concept_conformance.compile.pass.cpp
index 1443f2523a43f..1b7504e18f74f 100644
--- a/libcxx/test/std/utilities/optional/iterator_concept_conformance.compile.pass.cpp
+++ b/libcxx/test/std/utilities/optional/iterator_concept_conformance.compile.pass.cpp
@@ -20,3 +20,5 @@ static_assert(!std::indirectly_writable<std::optional<int>, int>);
 static_assert(!std::weakly_incrementable<std::optional<int> >);
 static_assert(!std::indirectly_movable<std::optional<int>, std::optional<int>>);
 static_assert(!std::indirectly_movable_storable<std::optional<int>, std::optional<int>>);
+static_assert(!std::indirectly_copyable<std::optional<int>, std::optional<int>>);
+static_assert(!std::indirectly_copyable_storable<std::optional<int>, std::optional<int>>);


        


More information about the libcxx-commits mailing list