diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -59,8 +59,8 @@ `[projected] `_,`ranges::projected `_,[iterator.concepts],Louis Dionne,✅ `[common.alg.req] `_: pt. 1,"| `indirectly_movable `_ | `indirectly_movable_storable `_ -| indirectly_copyable -| indirectly_copyable_storable",[iterator.concepts],Zoe Carver,In progress +| `indirectly_copyable `_ +| `indirectly_copyable_storable `_",[iterator.concepts],Zoe Carver and Konstantin Varlamov,✅ `[common.alg.req] `_: pt. 2,`indirectly_swappable `_,"| [iterator.concepts] | [iterator.cust.swap]",Zoe Carver,✅ `[common.alg.req] `_: pt. 3,`indirectly_comparable `_,[projected],Nikolas Klauser,✅ diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h --- a/libcxx/include/__iterator/concepts.h +++ b/libcxx/include/__iterator/concepts.h @@ -254,6 +254,22 @@ constructible_from, iter_rvalue_reference_t<_In>> && assignable_from&, iter_rvalue_reference_t<_In>>; +template +concept indirectly_copyable = + indirectly_readable<_In> && + indirectly_writable<_Out, iter_reference_t<_In>>; + +template +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> && + constructible_from, iter_reference_t<_In>> && + assignable_from&, 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 --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -136,6 +136,13 @@ template concept indirectly_movable_storable = see below; // since C++20 +// [alg.req.ind.copy], concept indirectly_copyable +template + concept indirectly_copyable = see below; // since C++20 + +template + concept indirectly_copyable_storable = see below; // since C++20 + // [alg.req.ind.swap], concept indirectly_swappable template 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 --- 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); static_assert( std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert( std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::bidirectional_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 --- 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); static_assert( std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert( std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::bidirectional_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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::bidirectional_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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::bidirectional_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 --- 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_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert( std::indirectly_swappable); static_assert(std::contiguous_iterator); @@ -58,4 +66,12 @@ static_assert( std::indirectly_movable_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); static_assert(std::random_access_iterator); @@ -61,4 +69,12 @@ static_assert( std::indirectly_movable_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); static_assert(std::forward_iterator); @@ -43,4 +47,8 @@ static_assert( std::indirectly_movable_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); static_assert(std::bidirectional_iterator); @@ -61,4 +69,12 @@ static_assert( std::indirectly_movable_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); static_assert( std::random_access_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 --- 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_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); static_assert( std::contiguous_iterator); @@ -63,4 +71,12 @@ static_assert( std::indirectly_movable_storable); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable*>); static_assert(!std::indirectly_movable_storable*>); +static_assert(std::indirectly_copyable*>); +static_assert(!std::indirectly_copyable_storable*>); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -54,6 +58,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -65,4 +71,6 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -43,6 +45,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -53,6 +57,8 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::forward_iterator); @@ -64,4 +70,6 @@ static_assert(!std::sized_sentinel_for); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- 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); static_assert(std::indirectly_movable); static_assert(std::indirectly_movable_storable); +static_assert(std::indirectly_copyable); +static_assert(std::indirectly_copyable_storable); static_assert(std::indirectly_swappable); 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 --- 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::sized_sentinel_for); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); static_assert(std::input_iterator); @@ -35,4 +37,6 @@ static_assert(!std::sized_sentinel_for); static_assert(!std::indirectly_movable); static_assert(!std::indirectly_movable_storable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable_storable); static_assert(!std::indirectly_swappable); 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 --- /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 +// concept indirectly_copyable; + +#include + +#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); +static_assert( std::indirectly_copyable); + +// Can't copy if the output pointer is const. +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); + +// Can copy from a pointer into an array but arrays aren't considered indirectly copyable-from. +static_assert( std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); + +// Can't copy between non-pointer types. +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); + +// Check some less common types. +static_assert(!std::indirectly_movable); +static_assert(!std::indirectly_movable); +static_assert(!std::indirectly_movable); +static_assert(!std::indirectly_movable); +static_assert(!std::indirectly_movable); + +// Can't copy move-only objects. +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert(!std::indirectly_copyable); + +// Can copy copy-only objects. +static_assert( std::indirectly_copyable); +static_assert(!std::indirectly_copyable); +static_assert( std::indirectly_copyable); +static_assert(!std::indirectly_copyable); + +template +struct PointerTo { + using value_type = T; + T& operator*() const; +}; + +// Can copy through a dereferenceable class. +static_assert( std::indirectly_copyable>); +static_assert(!std::indirectly_copyable>); +static_assert( std::indirectly_copyable, PointerTo>); +static_assert(!std::indirectly_copyable, PointerTo>); +static_assert( std::indirectly_copyable>); +static_assert( std::indirectly_copyable, CopyOnly*>); +static_assert( std::indirectly_copyable, PointerTo>); 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.copy/indirectly_copyable.subsumption.compile.pass.cpp copy from libcxx/test/std/iterators/iterator.requirements/alg.req.ind.move/indirectly_movable.subsumption.compile.pass.cpp copy to libcxx/test/std/iterators/iterator.requirements/alg.req.ind.copy/indirectly_copyable.subsumption.compile.pass.cpp --- 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.copy/indirectly_copyable.subsumption.compile.pass.cpp @@ -10,21 +10,19 @@ // UNSUPPORTED: libcpp-no-concepts // template -// concept indirectly_movable; +// concept indirectly_copyable; #include -#include - template -constexpr bool indirectly_movable_subsumption() { +constexpr bool indirectly_copyable_subsumption() { return false; } template - requires std::indirectly_movable -constexpr bool indirectly_movable_subsumption() { + requires std::indirectly_copyable +constexpr bool indirectly_copyable_subsumption() { return true; } -static_assert(indirectly_movable_subsumption()); +static_assert(indirectly_copyable_subsumption()); 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 --- /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 +// concept indirectly_copyable_storable; + +#include + +#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 +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); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert( std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable, PointerTo>); +// `indirectly_copyable_storable` requires the type to be `copyable`, which in turns requires it to be `movable`. +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable, PointerTo>); + +// The dereference operator returns a different 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>); +static_assert(!std::indirectly_writable&>); +static_assert( std::indirectly_writable&>); +static_assert( std::indirectly_writable&&>); +static_assert( std::indirectly_writable&&>); +static_assert(!std::indirectly_copyable_storable); + +// The dereference operator returns a different 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>); +static_assert( std::indirectly_writable&>); +static_assert(!std::indirectly_writable&>); +static_assert( std::indirectly_writable&&>); +static_assert( std::indirectly_writable&&>); +static_assert(!std::indirectly_copyable_storable); + +// The dereference operator returns a different 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>); +static_assert( std::indirectly_writable&>); +static_assert( std::indirectly_writable&>); +static_assert(!std::indirectly_writable&&>); +static_assert( std::indirectly_writable&&>); +static_assert(!std::indirectly_copyable_storable); + +// The dereference operator returns a different 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>); +static_assert( std::indirectly_writable&>); +static_assert( std::indirectly_writable&>); +static_assert( std::indirectly_writable&&>); +static_assert(!std::indirectly_writable&&>); +static_assert(!std::indirectly_copyable_storable); + +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); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); +static_assert(!std::indirectly_copyable_storable); + +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); + +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