Skip to content

Commit 97e383a

Browse files
committed
[libc++] Add std::ranges::iter_move and std::iter_rvalue_reference_t
Original patch by @cjdb, modified by @ldionne. Differential Revision: https://reviews.llvm.org/D99873
1 parent 861eff2 commit 97e383a

File tree

8 files changed

+442
-4
lines changed

8 files changed

+442
-4
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ set(files
1212
__functional_base_03
1313
__hash_table
1414
__iterator/concepts.h
15-
__iterator/iterator_traits.h
1615
__iterator/incrementable_traits.h
16+
__iterator/iter_move.h
17+
__iterator/iterator_traits.h
1718
__iterator/readable_traits.h
1819
__libcpp_version
1920
__locale

libcxx/include/__iterator/iter_move.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___ITERATOR_ITER_MOVE_H
11+
#define _LIBCPP___ITERATOR_ITER_MOVE_H
12+
13+
#include <__config>
14+
#include <__iterator/concepts.h>
15+
#include <concepts> // __class_or_enum
16+
#include <type_traits>
17+
#include <utility>
18+
19+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20+
#pragma GCC system_header
21+
#endif
22+
23+
_LIBCPP_PUSH_MACROS
24+
#include <__undef_macros>
25+
26+
_LIBCPP_BEGIN_NAMESPACE_STD
27+
28+
#if !defined(_LIBCPP_HAS_NO_RANGES)
29+
30+
namespace ranges::__iter_move {
31+
void iter_move();
32+
33+
template<class _Ip>
34+
concept __unqualified_iter_move = requires(_Ip&& __i) {
35+
iter_move(_VSTD::forward<_Ip>(__i));
36+
};
37+
38+
// [iterator.cust.move]/1
39+
// The name ranges::iter_move denotes a customization point object.
40+
// The expression ranges::iter_move(E) for a subexpression E is
41+
// expression-equivalent to:
42+
struct __fn {
43+
// [iterator.cust.move]/1.1
44+
// iter_move(E), if E has class or enumeration type and iter_move(E) is a
45+
// well-formed expression when treated as an unevaluated operand, [...]
46+
template<class _Ip>
47+
requires __class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>
48+
[[nodiscard]] constexpr decltype(auto) operator()(_Ip&& __i) const
49+
noexcept(noexcept(iter_move(_VSTD::forward<_Ip>(__i))))
50+
{
51+
return iter_move(_VSTD::forward<_Ip>(__i));
52+
}
53+
54+
// [iterator.cust.move]/1.2
55+
// Otherwise, if the expression *E is well-formed:
56+
// 1.2.1 if *E is an lvalue, std::move(*E);
57+
// 1.2.2 otherwise, *E.
58+
template<class _Ip>
59+
requires (!(__class_or_enum<remove_cvref_t<_Ip>> && __unqualified_iter_move<_Ip>)) &&
60+
requires(_Ip&& __i) { *_VSTD::forward<_Ip>(__i); }
61+
[[nodiscard]] constexpr decltype(auto) operator()(_Ip&& __i) const
62+
noexcept(noexcept(*_VSTD::forward<_Ip>(__i)))
63+
{
64+
if constexpr (is_lvalue_reference_v<decltype(*_VSTD::forward<_Ip>(__i))>) {
65+
return _VSTD::move(*_VSTD::forward<_Ip>(__i));
66+
} else {
67+
return *_VSTD::forward<_Ip>(__i);
68+
}
69+
}
70+
71+
// [iterator.cust.move]/1.3
72+
// Otherwise, ranges::iter_move(E) is ill-formed.
73+
};
74+
} // namespace ranges::__iter_move
75+
76+
namespace ranges::inline __cpo {
77+
inline constexpr auto iter_move = __iter_move::__fn{};
78+
}
79+
80+
template<__dereferenceable _Tp>
81+
requires requires(_Tp& __t) { { ranges::iter_move(__t) } -> __referenceable; }
82+
using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<_Tp&>()));
83+
84+
#endif // !_LIBCPP_HAS_NO_RANGES
85+
86+
_LIBCPP_END_NAMESPACE_STD
87+
88+
_LIBCPP_POP_MACROS
89+
90+
#endif // _LIBCPP___ITERATOR_ITER_MOVE_H

libcxx/include/concepts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,16 @@ concept copy_constructible =
246246
constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp> &&
247247
constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
248248

249+
// Whether a type is a class type or enumeration type according to the Core wording.
250+
template<class _Tp>
251+
concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
252+
249253
// [concept.swappable]
250254
namespace ranges::__swap {
251255
// Deleted to inhibit ADL
252256
template<class _Tp>
253257
void swap(_Tp&, _Tp&) = delete;
254258

255-
template<class _Tp>
256-
concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
257259

258260
// [1]
259261
template<class _Tp, class _Up>
@@ -440,7 +442,7 @@ concept equivalence_relation = relation<_Rp, _Tp, _Up>;
440442
template<class _Rp, class _Tp, class _Up>
441443
concept strict_weak_order = relation<_Rp, _Tp, _Up>;
442444

443-
#endif //_LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
445+
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
444446

445447
_LIBCPP_END_NAMESPACE_STD
446448

libcxx/include/iterator

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ struct iterator_traits<T*>;
3535
template<dereferenceable T>
3636
using iter_reference_t = decltype(*declval<T&>());
3737
38+
namespace ranges::inline unspecified {
39+
inline constexpr unspecified iter_move = unspecified; // since C++20, nodiscard as an extension
40+
}}
41+
42+
template<dereferenceable T>
43+
requires ...
44+
using iter_rvalue_reference_t = decltype(ranges::iter_move(declval<T&>())); // since C++20
45+
3846
template<class Category, class T, class Distance = ptrdiff_t,
3947
class Pointer = T*, class Reference = T&>
4048
struct iterator
@@ -422,6 +430,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
422430
#include <cstddef>
423431
#include <initializer_list>
424432
#include <__iterator/incrementable_traits.h>
433+
#include <__iterator/iter_move.h>
425434
#include <__iterator/iterator_traits.h>
426435
#include <__iterator/readable_traits.h>
427436
#include <__memory/addressof.h>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
// UNSUPPORTED: libcpp-no-concepts
11+
// UNSUPPORTED: gcc-10
12+
13+
// Test the [[nodiscard]] extension in libc++.
14+
// REQUIRES: libc++
15+
16+
// template<class I>
17+
// unspecified iter_move;
18+
19+
#include <iterator>
20+
21+
struct WithADL {
22+
WithADL() = default;
23+
constexpr decltype(auto) operator*() const noexcept;
24+
constexpr WithADL& operator++() noexcept;
25+
constexpr void operator++(int) noexcept;
26+
constexpr bool operator==(WithADL const&) const noexcept;
27+
friend constexpr auto iter_move(WithADL&) { return 0; }
28+
};
29+
30+
int main(int, char**) {
31+
int* noADL = nullptr;
32+
std::ranges::iter_move(noADL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
33+
34+
WithADL adl;
35+
std::ranges::iter_move(adl); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
36+
37+
return 0;
38+
}

0 commit comments

Comments
 (0)