Skip to content

Commit cb3de24

Browse files
H-G-HristovZingam
andauthored
[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 <[email protected]>
1 parent 38f1dd2 commit cb3de24

11 files changed

+47
-41
lines changed

libcxx/docs/ReleaseNotes/19.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Implemented Papers
4848
- P2944R3 - Comparisons for ``reference_wrapper`` (comparison operators for ``reference_wrapper`` only)
4949
- P2591R5 - Concatenation of strings and string views
5050
- P2968R2 - Make ``std::ignore`` a first-class object
51+
- P2997R1 - Removing the common reference requirement from the indirectly invocable concepts (as DR against C++20)
5152
- P2302R4 - ``std::ranges::contains``
5253
- P1659R3 - ``std::ranges::starts_with`` and ``std::ranges::ends_with``
5354
- P3029R1 - Better ``mdspan``'s CTAD

libcxx/docs/Status/Cxx2c.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Paper Status
4343
.. [#note-P3142R0] This paper is applied as DR against C++23. (MSVC STL and libstdc++ will do the same.)
4444
.. [#note-P2944R3] Implemented comparisons for ``reference_wrapper`` only.
4545
.. [#note-P2422R1] Libc++ keeps the ``nodiscard`` attributes as a conforming extension.
46+
.. [#note-P2997R1] This paper is applied as DR against C++20. (MSVC STL and libstdc++ will do the same.)
4647
4748
.. _issues-status-cxx2c:
4849

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"`P3029R1 <https://wg21.link/P3029R1>`__","LWG","Better ``mdspan``'s CTAD","Tokyo March 2024","|Complete|","19.0",""
6565
"","","","","","",""
6666
"`P2747R2 <https://wg21.link/P2747R2>`__","CWG","``constexpr`` placement new","St. Louis June 2024","","",""
67-
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","","",""
67+
"`P2997R1 <https://wg21.link/P2997R1>`__","LWG","Removing the common reference requirement from the indirectly invocable concepts","St. Louis June 2024","|Complete| [#note-P2997R1]_","19.0",""
6868
"`P2389R2 <https://wg21.link/P2389R2>`__","LWG","``dextents`` Index Type Parameter","St. Louis June 2024","|Complete|","19.0",""
6969
"`P3168R2 <https://wg21.link/P3168R2>`__","LWG","Give ``std::optional`` Range Support","St. Louis June 2024","","","|ranges|"
7070
"`P3217R0 <https://wg21.link/P3217R0>`__","LWG","Adjoints to 'Enabling list-initialization for algorithms': find_last","St. Louis June 2024","","",""

libcxx/include/__iterator/concepts.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,46 +177,43 @@ concept __has_arrow = input_iterator<_Ip> && (is_pointer_v<_Ip> || requires(_Ip
177177
template <class _Fp, class _It>
178178
concept indirectly_unary_invocable =
179179
indirectly_readable<_It> && copy_constructible<_Fp> && invocable<_Fp&, iter_value_t<_It>&> &&
180-
invocable<_Fp&, iter_reference_t<_It>> && invocable<_Fp&, iter_common_reference_t<_It>> &&
180+
invocable<_Fp&, iter_reference_t<_It>> &&
181181
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;
182182

183183
template <class _Fp, class _It>
184184
concept indirectly_regular_unary_invocable =
185185
indirectly_readable<_It> && copy_constructible<_Fp> && regular_invocable<_Fp&, iter_value_t<_It>&> &&
186-
regular_invocable<_Fp&, iter_reference_t<_It>> && regular_invocable<_Fp&, iter_common_reference_t<_It>> &&
186+
regular_invocable<_Fp&, iter_reference_t<_It>> &&
187187
common_reference_with< invoke_result_t<_Fp&, iter_value_t<_It>&>, invoke_result_t<_Fp&, iter_reference_t<_It>>>;
188188

189189
template <class _Fp, class _It>
190190
concept indirect_unary_predicate =
191191
indirectly_readable<_It> && copy_constructible<_Fp> && predicate<_Fp&, iter_value_t<_It>&> &&
192-
predicate<_Fp&, iter_reference_t<_It>> && predicate<_Fp&, iter_common_reference_t<_It>>;
192+
predicate<_Fp&, iter_reference_t<_It>>;
193193

194194
template <class _Fp, class _It1, class _It2>
195195
concept indirect_binary_predicate =
196196
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
197197
predicate<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
198198
predicate<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
199199
predicate<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
200-
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
201-
predicate<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
200+
predicate<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;
202201

203202
template <class _Fp, class _It1, class _It2 = _It1>
204203
concept indirect_equivalence_relation =
205204
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
206205
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
207206
equivalence_relation<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
208207
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
209-
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
210-
equivalence_relation<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
208+
equivalence_relation<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;
211209

212210
template <class _Fp, class _It1, class _It2 = _It1>
213211
concept indirect_strict_weak_order =
214212
indirectly_readable<_It1> && indirectly_readable<_It2> && copy_constructible<_Fp> &&
215213
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_value_t<_It2>&> &&
216214
strict_weak_order<_Fp&, iter_value_t<_It1>&, iter_reference_t<_It2>> &&
217215
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_value_t<_It2>&> &&
218-
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>> &&
219-
strict_weak_order<_Fp&, iter_common_reference_t<_It1>, iter_common_reference_t<_It2>>;
216+
strict_weak_order<_Fp&, iter_reference_t<_It1>, iter_reference_t<_It2>>;
220217

221218
template <class _Fp, class... _Its>
222219
requires(indirectly_readable<_Its> && ...) && invocable<_Fp, iter_reference_t<_Its>...>

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_binary_predicate.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ struct BadPredicate5 {
7676
};
7777
static_assert(!std::indirect_binary_predicate<BadPredicate5, It1, It2>);
7878

79-
// Should fail when the predicate can't be called with (iter_common_reference_t, iter_common_reference_t)
80-
struct BadPredicate6 {
81-
template <class T, class U> bool operator()(T const&, U const&) const;
82-
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
79+
// This case was made valid by P2997R1.
80+
struct GoodPredicate6 {
81+
template <class T, class U>
82+
bool operator()(T const&, U const&) const;
83+
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
8384
};
84-
static_assert(!std::indirect_binary_predicate<BadPredicate6, It1, It2>);
85+
static_assert(std::indirect_binary_predicate<GoodPredicate6, It1, It2>);
8586

8687
// Test ADL-proofing (P2538R1)
8788
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_equivalence_relation.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,13 @@ struct BadRelation5 {
9191
};
9292
static_assert(!std::indirect_equivalence_relation<BadRelation5, It1, It2>);
9393

94-
// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
95-
struct BadRelation6 {
96-
template <class T, class U> bool operator()(T const&, U const&) const;
97-
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
94+
// This case was made valid by P2997R1.
95+
struct GoodRelation6 {
96+
template <class T, class U>
97+
bool operator()(T const&, U const&) const;
98+
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
9899
};
99-
static_assert(!std::indirect_equivalence_relation<BadRelation6, It1, It2>);
100+
static_assert(std::indirect_equivalence_relation<GoodRelation6, It1, It2>);
100101

101102
// Test ADL-proofing (P2538R1)
102103
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_strict_weak_order.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,13 @@ struct BadOrder5 {
9191
};
9292
static_assert(!std::indirect_strict_weak_order<BadOrder5, It1, It2>);
9393

94-
// Should fail when the function can't be called with (iter_common_reference_t, iter_common_reference_t)
95-
struct BadOrder6 {
96-
template <class T, class U> bool operator()(T const&, U const&) const;
97-
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
94+
// This case was made valid by P2997R1.
95+
struct GoodOrder6 {
96+
template <class T, class U>
97+
bool operator()(T const&, U const&) const;
98+
bool operator()(std::iter_common_reference_t<It1>, std::iter_common_reference_t<It2>) const = delete;
9899
};
99-
static_assert(!std::indirect_strict_weak_order<BadOrder6, It1, It2>);
100+
static_assert(std::indirect_strict_weak_order<GoodOrder6, It1, It2>);
100101

101102
// Test ADL-proofing (P2538R1)
102103
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirect_unary_predicate.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,13 @@ struct BadPredicate3 {
5757
};
5858
static_assert(!std::indirect_unary_predicate<BadPredicate3, It>);
5959

60-
// Should fail when the predicate can't be called with std::iter_common_reference_t<It>
61-
struct BadPredicate4 {
62-
template <class T> bool operator()(T const&) const;
63-
bool operator()(std::iter_common_reference_t<It>) const = delete;
60+
// This case was made valid by P2997R1.
61+
struct GoodPredicate4 {
62+
template <class T>
63+
bool operator()(T const&) const;
64+
bool operator()(std::iter_common_reference_t<It>) const = delete;
6465
};
65-
static_assert(!std::indirect_unary_predicate<BadPredicate4, It>);
66+
static_assert(std::indirect_unary_predicate<GoodPredicate4, It>);
6667

6768
// Test ADL-proofing (P2538R1)
6869
#if TEST_STD_VER >= 26 || defined(_LIBCPP_VERSION)

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_regular_unary_invocable.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,13 @@ struct BadInvocable3 {
5656
};
5757
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable3, It>);
5858

59-
// Should fail when the invocable can't be called with (iter_common_reference_t)
60-
struct BadInvocable4 {
61-
template <class T> R1 operator()(T const&) const;
62-
R1 operator()(std::iter_common_reference_t<It>) const = delete;
59+
// This case was made valid by P2997R1.
60+
struct GoodInvocable4 {
61+
template <class T>
62+
R1 operator()(T const&) const;
63+
R1 operator()(std::iter_common_reference_t<It>) const = delete;
6364
};
64-
static_assert(!std::indirectly_regular_unary_invocable<BadInvocable4, It>);
65+
static_assert(std::indirectly_regular_unary_invocable<GoodInvocable4, It>);
6566

6667
// Should fail when the invocable doesn't have a common reference between its return types
6768
struct BadInvocable5 {

libcxx/test/std/iterators/iterator.requirements/indirectcallable/indirectinvocable/indirectly_unary_invocable.compile.pass.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,13 @@ struct BadInvocable3 {
5656
};
5757
static_assert(!std::indirectly_unary_invocable<BadInvocable3, It>);
5858

59-
// Should fail when the invocable can't be called with (iter_common_reference_t)
60-
struct BadInvocable4 {
61-
template <class T> R1 operator()(T const&) const;
62-
R1 operator()(std::iter_common_reference_t<It>) const = delete;
59+
// This case was made valid by P2997R1.
60+
struct GoodInvocable4 {
61+
template <class T>
62+
R1 operator()(T const&) const;
63+
R1 operator()(std::iter_common_reference_t<It>) const = delete;
6364
};
64-
static_assert(!std::indirectly_unary_invocable<BadInvocable4, It>);
65+
static_assert(std::indirectly_unary_invocable<GoodInvocable4, It>);
6566

6667
// Should fail when the invocable doesn't have a common reference between its return types
6768
struct BadInvocable5 {

libcxx/utils/generate_feature_test_macro_components.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,8 @@ def add_version_header(tc):
993993
"name": "__cpp_lib_ranges",
994994
"values": {
995995
"c++20": 202207,
996-
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts
996+
# "c++23": 202302, # Relaxing Ranges Just A Smidge
997+
# "c++26": 202406, # P2997R1 Removing the common reference requirement from the indirectly invocable concepts (already implemented as a DR)
997998
},
998999
"headers": ["algorithm", "functional", "iterator", "memory", "ranges"],
9991000
},

0 commit comments

Comments
 (0)