diff --git a/libcxx/include/__iterator/iter_move.h b/libcxx/include/__iterator/iter_move.h --- a/libcxx/include/__iterator/iter_move.h +++ b/libcxx/include/__iterator/iter_move.h @@ -32,10 +32,12 @@ void iter_move(); -template -concept __unqualified_iter_move = requires(_Ip&& __i) { - iter_move(_VSTD::forward<_Ip>(__i)); -}; +template +concept __unqualified_iter_move = + __class_or_enum> && + requires (_Tp&& __t) { + iter_move(_VSTD::forward<_Tp>(__t)); + }; // [iterator.cust.move]/1 // The name ranges::iter_move denotes a customization point object. diff --git a/libcxx/include/__iterator/iter_swap.h b/libcxx/include/__iterator/iter_swap.h --- a/libcxx/include/__iterator/iter_swap.h +++ b/libcxx/include/__iterator/iter_swap.h @@ -36,9 +36,11 @@ void iter_swap(_I1, _I2) = delete; template - concept __unqualified_iter_swap = requires(_T1&& __x, _T2&& __y) { - iter_swap(_VSTD::forward<_T1>(__x), _VSTD::forward<_T2>(__y)); - }; + concept __unqualified_iter_swap = + (__class_or_enum> || __class_or_enum>) && + requires (_T1&& __x, _T2&& __y) { + iter_swap(_VSTD::forward<_T1>(__x), _VSTD::forward<_T2>(__y)); + }; template concept __readable_swappable = diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.move/iter_move.pass.cpp @@ -21,6 +21,8 @@ #include "../unqualified_lookup_wrapper.h" +using IterMoveT = decltype(std::ranges::iter_move); + // Wrapper around an iterator for testing `iter_move` when an unqualified call to `iter_move` isn't // possible. template @@ -113,7 +115,7 @@ constexpr bool operator==(WithoutADL const&) const; }; -constexpr bool check_iter_move() { +constexpr bool test() { constexpr int full_size = 100; constexpr int half_size = full_size / 2; constexpr int reset = 0; @@ -173,18 +175,19 @@ return true; } -template -concept can_iter_move = requires (T t) { std::ranges::iter_move(t); }; +static_assert(!std::is_invocable_v); // too many arguments +static_assert(!std::is_invocable_v); -int main(int, char**) { - static_assert(check_iter_move()); - check_iter_move(); +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(std::is_invocable_v**>); +static_assert(std::is_invocable_v**&>); - // Make sure that `iter_move` SFINAEs away when the type can't be iter_move'd - { - struct NoIterMove { }; - static_assert(!can_iter_move); - } +int main(int, char**) +{ + test(); + static_assert(test()); return 0; } diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp @@ -24,7 +24,7 @@ struct HasIterSwap { int &value_; - explicit HasIterSwap(int &value) : value_(value) { assert(value == 0); } + constexpr explicit HasIterSwap(int &value) : value_(value) { assert(value == 0); } friend constexpr void iter_swap(HasIterSwap& a, HasIterSwap& b) { a.value_ = 1; @@ -56,7 +56,7 @@ struct HasRangesSwap { int &value_; - explicit HasRangesSwap(int &value) : value_(value) { assert(value == 0); } + constexpr explicit HasRangesSwap(int &value) : value_(value) { assert(value == 0); } friend constexpr void swap(HasRangesSwap& a, HasRangesSwap& b) { a.value_ = 1; @@ -72,9 +72,9 @@ using value_type = HasRangesSwap; HasRangesSwap &value_; - explicit HasRangesSwapWrapper(HasRangesSwap &value) : value_(value) {} + constexpr explicit HasRangesSwapWrapper(HasRangesSwap &value) : value_(value) {} - HasRangesSwap& operator*() const { return value_; } + constexpr HasRangesSwap& operator*() const { return value_; } }; static_assert( std::is_invocable_v); @@ -86,7 +86,7 @@ struct A { bool value = false; - A& operator=(const B&) { + constexpr A& operator=(const B&) { value = true; return *this; }; @@ -94,7 +94,7 @@ struct B { bool value = false; - B& operator=(const A&) { + constexpr B& operator=(const A&) { value = true; return *this; }; @@ -111,7 +111,7 @@ MoveOnly1(const MoveOnly1&) = delete; MoveOnly1& operator=(const MoveOnly1&) = delete; - MoveOnly1& operator=(MoveOnly2 &&) { + constexpr MoveOnly1& operator=(MoveOnly2 &&) { value = true; return *this; }; @@ -126,13 +126,14 @@ MoveOnly2(const MoveOnly2&) = delete; MoveOnly2& operator=(const MoveOnly2&) = delete; - MoveOnly2& operator=(MoveOnly1 &&) { + constexpr MoveOnly2& operator=(MoveOnly1 &&) { value = true; return *this; }; }; -int main(int, char**) { +constexpr bool test() +{ { int value1 = 0; int value2 = 0; @@ -140,7 +141,6 @@ std::ranges::iter_swap(a, b); assert(value1 == 1 && value2 == 1); } - { int value1 = 0; int value2 = 0; @@ -149,7 +149,6 @@ std::ranges::iter_swap(cWrapper, dWrapper); assert(value1 == 1 && value2 == 1); } - { int value1 = 0; int value2 = 0; @@ -157,7 +156,6 @@ std::ranges::iter_swap(HasRangesSwapWrapper(c), HasRangesSwapWrapper(d)); assert(value1 == 1 && value2 == 1); } - { A e; B f; A *ePtr = &e; @@ -165,19 +163,20 @@ std::ranges::iter_swap(ePtr, fPtr); assert(e.value && f.value); } - { MoveOnly1 g; MoveOnly2 h; std::ranges::iter_swap(&g, &h); assert(g.value && h.value); } - { auto arr = std::array(); std::ranges::iter_swap(arr.begin(), arr.begin() + 1); - assert(arr[0].moves() == 1 && arr[1].moves() == 2); + if (std::is_constant_evaluated()) { + assert(arr[0].moves() == 1 && arr[1].moves() == 3); + } else { + assert(arr[0].moves() == 1 && arr[1].moves() == 2); + } } - { int buff[2] = {1, 2}; std::ranges::iter_swap(buff + 0, buff + 1); @@ -201,6 +200,27 @@ std::ranges::iter_swap(contiguous_iterator(buff), contiguous_iterator(buff + 1)); assert(buff[0] == 2 && buff[1] == 1); } + return true; +} + +static_assert(!std::is_invocable_v); // too few arguments +static_assert(!std::is_invocable_v); // too many arguments +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); + +// Test ADL-proofing. +struct Incomplete; +template struct Holder { T t; }; +static_assert(std::is_invocable_v**, Holder**>); +static_assert(std::is_invocable_v**, Holder**&>); +static_assert(std::is_invocable_v**&, Holder**>); +static_assert(std::is_invocable_v**&, Holder**&>); + +int main(int, char**) +{ + test(); + static_assert(test()); return 0; } diff --git a/libcxx/test/std/ranges/range.req/range.refinements/bidirectional_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/bidirectional_range.compile.pass.cpp --- a/libcxx/test/std/ranges/range.req/range.refinements/bidirectional_range.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.req/range.refinements/bidirectional_range.compile.pass.cpp @@ -17,8 +17,6 @@ #include "test_range.h" - - template