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 @@ -107,6 +107,14 @@ requires { typename _ITER_CONCEPT<_Ip>; } && derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; +// [iterator.concept.forward] +template +concept forward_iterator = + input_iterator<_Ip> && + derived_from<_ITER_CONCEPT<_Ip>, forward_iterator_tag> && + incrementable<_Ip> && + sentinel_for<_Ip, _Ip>; + // clang-format on #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -57,8 +57,12 @@ template concept input_range = range<_Tp> && input_iterator >; + template + concept forward_range = input_range<_Tp> && forward_iterator >; + template concept common_range = range<_Tp> && same_as, sentinel_t<_Tp> >; + } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -72,6 +72,10 @@ template concept input_iterator = see below; // since C++20 +// [iterator.concept.forward], concept forward_­iterator +template + concept forward_iterator = see below; // since C++20 + template struct iterator diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -51,6 +51,9 @@ template concept input_range = see below; + template + concept forward_range = see below; + template concept common_range = see below; } diff --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp @@ -23,8 +23,8 @@ static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ static_assert(std::same_as, fs::path::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, fs::path::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/forward_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/forward_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/forward_iterator.compile.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// template +// concept forward_iterator; + +#include + +#include + +#include "test_iterators.h" + +static_assert(std::forward_iterator >); +static_assert(std::forward_iterator >); +static_assert(std::forward_iterator >); +static_assert(std::forward_iterator >); + +// TODO: add new `cxx20_*_iterator`s as they're added +static_assert(!std::forward_iterator >); +static_assert(std::forward_iterator >); + +static_assert(std::forward_iterator); +static_assert(std::forward_iterator); +static_assert(std::forward_iterator); +static_assert(std::forward_iterator); + +struct not_input_iterator { + using difference_type = std::ptrdiff_t; + using iterator_concept = std::forward_iterator_tag; + + int operator*() const; + + not_input_iterator& operator++(); + not_input_iterator operator++(int); +}; +static_assert(std::input_or_output_iterator && !std::input_iterator && + !std::forward_iterator); + +struct not_equality_comparable { + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = std::forward_iterator_tag; + + int operator*() const; + + not_equality_comparable& operator++(); + not_equality_comparable operator++(int); +}; +static_assert(std::input_iterator && !std::forward_iterator); diff --git a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/subsumption.compile.pass.cpp copy from libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp copy to libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/subsumption.compile.pass.cpp --- a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.forward/subsumption.compile.pass.cpp @@ -12,29 +12,24 @@ // XFAIL: msvc && clang // template -// concept input_iterator; - -#include +// concept forward_iterator; #include -struct range { - int* begin(); - int* end(); -}; +#include // clang-format off -template -requires std::input_iterator > -[[nodiscard]] constexpr bool check_input_range_subsumption() { +template +requires std::derived_from, std::forward_iterator_tag> +[[nodiscard]] constexpr bool check_subsumption() { return false; } -template +template requires true -[[nodiscard]] constexpr bool check_input_range_subsumption() { +[[nodiscard]] constexpr bool check_subsumption() { return true; } // clang-format on -static_assert(check_input_range_subsumption()); +static_assert(check_subsumption()); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp @@ -20,6 +20,7 @@ static_assert(std::input_iterator >); static_assert(std::input_iterator >); +static_assert(std::input_iterator >); struct no_explicit_iter_concept { using value_type = int; diff --git a/libcxx/test/std/ranges/range.refinements/forward_range.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/forward_range.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.refinements/forward_range.compile.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// template +// concept forward_range; + +#include + +#include "test_iterators.h" +#include "test_range.h" + +namespace stdr = std::ranges; + +static_assert(stdr::forward_range >); +static_assert(stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); + +static_assert(!stdr::forward_range >); +static_assert(!stdr::forward_range const>); diff --git a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp --- a/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.refinements/subsumption.compile.pass.cpp @@ -38,3 +38,19 @@ // clang-format on static_assert(check_input_range_subsumption()); + +// clang-format off +template +requires std::forward_iterator > +[[nodiscard]] constexpr bool check_forward_range_subsumption() { + return false; +} + +template +requires true +[[nodiscard]] constexpr bool check_forward_range_subsumption() { + return true; +} +// clang-format on + +static_assert(check_forward_range_subsumption()); diff --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ static_assert(std::same_as, std::cmatch::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, std::cmatch::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ static_assert(std::same_as, std::string::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, std::string::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp @@ -22,8 +22,8 @@ static_assert(std::same_as, std::string_view::iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); static_assert(std::same_as, std::string_view::const_iterator>); static_assert(stdr::common_range); -static_assert(stdr::input_range); +static_assert(stdr::forward_range); diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -667,6 +667,34 @@ I base_ = I(); }; +template +struct cxx20_forward_iterator { + using value_type = std::iter_value_t; + using difference_type = std::iter_difference_t; + using iterator_concept = std::forward_iterator_tag; + + cxx20_forward_iterator() = default; + + explicit constexpr cxx20_forward_iterator(I base) : base_(std::move(base)) {} + + constexpr decltype(auto) operator*() const { return *base_; } + + cxx20_forward_iterator& operator++() { + ++base_; + return *this; + } + cxx20_forward_iterator operator++(int) { + auto temp = *this; + ++*this; + return *this; + } + + bool operator==(cxx20_forward_iterator const&) const = default; + +private: + I base_ = I(); +}; + #endif // TEST_STD_VER > 17 && defined(__cpp_lib_concepts) #undef DELETE_FUNCTION