From 442f478d89d75c9503a7016b8557734347bc06da Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Thu, 18 Jul 2024 14:54:29 +0300 Subject: [PATCH] [libc++][iterator][ranges] P2997R1: Removing the common reference requirement from the indirectly invocable concepts (#98817) Implements as DR against C++20: https://wg21.link/P2997R1 References: - https://eel.is/c++draft/indirectcallable.indirectinvocable - https://eel.is/c++draft/version.syn#header:%3cversion%3e --------- Co-authored-by: Hristo Hristov --- libcxx/docs/ReleaseNotes/19.rst | 1 + libcxx/docs/Status/Cxx2c.rst | 1 + libcxx/docs/Status/Cxx2cPapers.csv | 2 +- libcxx/include/__iterator/concepts.h | 15 ++++++--------- .../indirect_binary_predicate.compile.pass.cpp | 11 ++++++----- ...indirect_equivalence_relation.compile.pass.cpp | 11 ++++++----- .../indirect_strict_weak_order.compile.pass.cpp | 11 ++++++----- .../indirect_unary_predicate.compile.pass.cpp | 11 ++++++----- ...ectly_regular_unary_invocable.compile.pass.cpp | 11 ++++++----- .../indirectly_unary_invocable.compile.pass.cpp | 11 ++++++----- .../generate_feature_test_macro_components.py | 3 ++- 11 files changed, 47 insertions(+), 41 deletions(-) diff --git a/libcxx/docs/ReleaseNotes/19.rst b/libcxx/docs/ReleaseNotes/19.rst index 80f43256f1270c6..a28dae52e8579d9 100644 --- a/libcxx/docs/ReleaseNotes/19.rst +++ b/libcxx/docs/ReleaseNotes/19.rst @@ -48,6 +48,7 @@ Implemented Papers - P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only) - P2591R5 - Concatenation of strings and string views - P2968R2 - Make ``std::ignore`` a first-class object +- P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20) - P2302R4 - ``std::ranges::contains`` - P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with`` - P3029R1 - Better ``mdspan``'s CTAD diff --git a/libcxx/docs/Status/Cxx2c.rst b/libcxx/docs/Status/Cxx2c.rst index 03a6eeaa40c7995..1b8d96588c3cbae 100644 --- a/libcxx/docs/Status/Cxx2c.rst +++ b/libcxx/docs/Status/Cxx2c.rst @@ -43,6 +43,7 @@ Paper Status .. [#note-P3142R0] This paper is applied as DR against C++23. (MSVC STL and libstdc++ will do the same.) .. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only. .. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension. + .. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.) .. _issues-status-cxx2c: diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 968d82a973a79ab..130e4ef894f29cc 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -64,7 +64,7 @@ "`P3029R1 `__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0","" "","","","","","","" "`P2747R2 `__","CWG","``constexpr`` placement new","St. Louis June 2024","","","" -"`P2997R1 `__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","","","" +"`P2997R1 `__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","|Complete| [#note-P2997R1]_","19.0","" "`P2389R2 `__","LWG","``dextents`` Index Type Parameter","St. Louis June 2024","|Complete|","19.0","" "`P3168R2 `__","LWG","Give ``std::optional`` Range Support","St. Louis June 2024","","","|ranges|" "`P3217R0 `__","LWG","Adjoints to 'Enabling list-initialization for algorithms': find_last","St. Louis June 2024","","","" diff --git a/libcxx/include/__iterator/concepts.h b/libcxx/include/__iterator/concepts.h index afb7b821a99ce6d..0a4878308d55f00 100644 --- a/libcxx/include/__iterator/concepts.h +++ b/libcxx/include/__iterator/concepts.h @@ -177,19 +177,19 @@ concept __has_arrow = input_iterator<_Ip> && (is_pointer_v<_Ip> || requires(_Ip template concept indirectly_unary_invocable = indirectly_readable<_It> && copy_constructible<_Fp> && invocable<_Fp&, iter_value_t<_It>&> && - invocable<_Fp&, iter_reference_t<_It>> && invocable<_Fp&, iter_common_reference_t<_It>> && + invocable<_Fp&, iter_reference_t<_It>> && common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>; template concept indirectly_regular_unary_invocable = indirectly_readable<_It> && copy_constructible<_Fp> && regular_invocable<_Fp&, iter_value_t<_It>&> && - regular_invocable<_Fp&, iter_reference_t<_It>> && regular_invocable<_Fp&, iter_common_reference_t<_It>> && + regular_invocable<_Fp&, iter_reference_t<_It>> && common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>; template concept indirect_unary_predicate = indirectly_readable<_It> && copy_constructible<_Fp> && predicate<_Fp&, iter_value_t<_It>&> && - predicate<_Fp&, iter_reference_t<_It>> && predicate<_Fp&, iter_common_reference_t<_It>>; + predicate<_Fp&, iter_reference_t<_It>>; template concept indirect_binary_predicate = @@ -197,8 +197,7 @@ concept indirect_binary_predicate = predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && - predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && - predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; template concept indirect_equivalence_relation = @@ -206,8 +205,7 @@ concept indirect_equivalence_relation = equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && - equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && - equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; template concept indirect_strict_weak_order = @@ -215,8 +213,7 @@ concept indirect_strict_weak_order = strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> && strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> && strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> && - strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> && - strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>; + strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>; template requires(indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...> diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp index e04c50885282056..38dcd70d850e6c9 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp @@ -76,12 +76,13 @@ struct BadPredicate5 { }; static_assert(!std::indirect_binary_predicate); -// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t) -struct BadPredicate6 { - template bool operator()(T const&, U const&) const; - bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodPredicate6 { + template + bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirect_binary_predicate); +static_assert(std::indirect_binary_predicate); // Test ADL-proofing (P2538R1) #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp index 56f52f28ff6fe78..8ea7e8a6d9e1e7b 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp @@ -91,12 +91,13 @@ struct BadRelation5 { }; static_assert(!std::indirect_equivalence_relation); -// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) -struct BadRelation6 { - template bool operator()(T const&, U const&) const; - bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodRelation6 { + template + bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirect_equivalence_relation); +static_assert(std::indirect_equivalence_relation); // Test ADL-proofing (P2538R1) #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp index f36431c89f288d5..074725f97bf326f 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp @@ -91,12 +91,13 @@ struct BadOrder5 { }; static_assert(!std::indirect_strict_weak_order); -// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t) -struct BadOrder6 { - template bool operator()(T const&, U const&) const; - bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodOrder6 { + template + bool operator()(T const&, U const&) const; + bool operator()(std::iter_common_reference_t, std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirect_strict_weak_order); +static_assert(std::indirect_strict_weak_order); // Test ADL-proofing (P2538R1) #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp index 4551113af82e8b1..f52ea8f9151c3a1 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp @@ -57,12 +57,13 @@ struct BadPredicate3 { }; static_assert(!std::indirect_unary_predicate); -// Should fail when the predicate can't be called with std::iter_common_reference_t -struct BadPredicate4 { - template bool operator()(T const&) const; - bool operator()(std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodPredicate4 { + template + bool operator()(T const&) const; + bool operator()(std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirect_unary_predicate); +static_assert(std::indirect_unary_predicate); // Test ADL-proofing (P2538R1) #if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION) diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp index 9e0c3c99dee9885..fceae03a4b324c3 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp @@ -56,12 +56,13 @@ struct BadInvocable3 { }; static_assert(!std::indirectly_regular_unary_invocable); -// Should fail when the invocable can't be called with (iter_common_reference_t) -struct BadInvocable4 { - template R1 operator()(T const&) const; - R1 operator()(std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodInvocable4 { + template + R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirectly_regular_unary_invocable); +static_assert(std::indirectly_regular_unary_invocable); // Should fail when the invocable doesn't have a common reference between its return types struct BadInvocable5 { diff --git a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp index fc955eb88585a5d..27c078baeb19420 100644 --- a/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp @@ -56,12 +56,13 @@ struct BadInvocable3 { }; static_assert(!std::indirectly_unary_invocable); -// Should fail when the invocable can't be called with (iter_common_reference_t) -struct BadInvocable4 { - template R1 operator()(T const&) const; - R1 operator()(std::iter_common_reference_t) const = delete; +// This case was made valid by P2997R1. +struct GoodInvocable4 { + template + R1 operator()(T const&) const; + R1 operator()(std::iter_common_reference_t) const = delete; }; -static_assert(!std::indirectly_unary_invocable); +static_assert(std::indirectly_unary_invocable); // Should fail when the invocable doesn't have a common reference between its return types struct BadInvocable5 { diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index a267e5774e2ad58..65ba2f8455f1b6e 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -993,7 +993,8 @@ def add_version_header(tc): "name": "__cpp_lib_ranges", "values": { "c++20": 202207, - # "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts + # "c++23": 202302, # Relaxing Ranges Just A Smidge + # "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (already implemented as a DR) }, "headers": ["algorithm", "functional", "iterator", "memory", "ranges"], },