Skip to content

Commit 3f630cf

Browse files
committed
[libc++][ranges] Implement ranges::uninitialized_default_construct{,_n}.
Defined in [`specialized.algorithms`](wg21.link/specialized.algorithms). Also: - refactor the existing non-range implementation so that most of it can be shared between the range-based and non-range-based algorithms; - remove an existing test for the non-range version of `uninitialized_default_construct{,_n}` that likely triggered undefined behavior (it read the values of built-ins after default-initializing them, essentially reading uninitialized memory). Reviewed By: #libc, Quuxplusone, ldionne Differential Revision: https://reviews.llvm.org/D115315
1 parent 624f12d commit 3f630cf

File tree

17 files changed

+556
-75
lines changed

17 files changed

+556
-75
lines changed

libcxx/docs/Status/RangesPaper.csv

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ Section,Description,Dependencies,Assignee,Complete
1212
| `iter_difference_t <https://llvm.org/D99863>`_",,Christopher Di Bella,✅
1313
`[iterator.traits] <http://wg21.link/iterator.traits>`_,`Updates to iterator_traits <https://llvm.org/D99855>`_,"| indirectly_readable_traits
1414
| incrementable_traits",Christopher Di Bella,✅
15-
`[special.mem.concepts] <http://wg21.link/special.mem.concepts>`_,"| *no-throw-input-iterator*
16-
| *no-throw-sentinel-for*
17-
| *no-throw-input-range*
18-
| *no-throw-forward-iterator*
19-
| *no-throw-forward-range*","| [iterator.concepts]
15+
`[special.mem.concepts] <http://wg21.link/special.mem.concepts>`_,"| *nothrow-input-iterator*
16+
| *nothrow-sentinel-for*
17+
| *nothrow-input-range*
18+
| *nothrow-forward-iterator*
19+
| *nothrow-forward-range*","| [iterator.concepts]
2020
| [range.refinements]",Konstantin Varlamov,✅
21-
`[specialized.algorithms] <http://wg21.link/specialized.algorithms>`_,"| ranges::uninitialized_default_construct
22-
| ranges::uninitialized_default_construct_n
21+
`[specialized.algorithms] <http://wg21.link/specialized.algorithms>`_,"| `ranges::uninitialized_default_construct <https://llvm.org/D115315>`
22+
| `ranges::uninitialized_default_construct_n <https://llvm.org/D115315>`
2323
| ranges::uninitialized_value_construct
2424
| ranges::uninitialized_value_construct_n
2525
| ranges::uninitialized_copy
@@ -31,7 +31,7 @@ Section,Description,Dependencies,Assignee,Complete
3131
| ranges::construct_at
3232
| ranges::destroy
3333
| ranges::destroy_at
34-
| ranges::destroy_n",[special.mem.concepts],Konstantin Varlamov,Not started
34+
| ranges::destroy_n",[special.mem.concepts],Konstantin Varlamov,In progress
3535
[strings],Adds begin/end and updates const_iterator.,[iterator.concepts],Unassigned,Not started
3636
[views.span],Same as [strings],[iterator.concepts],Unassigned,Not started
3737
`[iterator.cust.move] <http://wg21.link/iterator.cust.move>`_,`ranges::iter_move <https://llvm.org/D99873>`_,,Zoe Carver,✅

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ set(files
231231
__memory/concepts.h
232232
__memory/construct_at.h
233233
__memory/pointer_traits.h
234+
__memory/ranges_uninitialized_algorithms.h
234235
__memory/raw_storage_iterator.h
235236
__memory/shared_ptr.h
236237
__memory/temporary_buffer.h

libcxx/include/__iterator/advance.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ void advance(_InputIter& __i, _Distance __orig_n) {
6969

7070
namespace ranges {
7171
// [range.iter.op.advance]
72+
// TODO(varconst): rename `__advance_fn` to `__fn`.
7273
struct __advance_fn final : private __function_like {
7374
private:
7475
template <class _Tp>

libcxx/include/__iterator/next.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
3939
#if !defined(_LIBCPP_HAS_NO_RANGES)
4040

4141
namespace ranges {
42+
// TODO(varconst): rename `__next_fn` to `__fn`.
4243
struct __next_fn final : private __function_like {
4344
_LIBCPP_HIDE_FROM_ABI
4445
constexpr explicit __next_fn(__tag __x) noexcept : __function_like(__x) {}

libcxx/include/__iterator/prev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
3838
#if !defined(_LIBCPP_HAS_NO_RANGES)
3939

4040
namespace ranges {
41+
// TODO(varconst): rename `__prev_fn` to `__fn`.
4142
struct __prev_fn final : private __function_like {
4243
_LIBCPP_HIDE_FROM_ABI
4344
constexpr explicit __prev_fn(__tag __x) noexcept : __function_like(__x) {}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H
11+
#define _LIBCPP___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H
12+
13+
#include <__concepts/constructible.h>
14+
#include <__config>
15+
#include <__function_like.h>
16+
#include <__iterator/incrementable_traits.h>
17+
#include <__iterator/iterator_traits.h>
18+
#include <__iterator/readable_traits.h>
19+
#include <__memory/concepts.h>
20+
#include <__memory/uninitialized_algorithms.h>
21+
#include <__ranges/access.h>
22+
#include <__ranges/concepts.h>
23+
#include <__ranges/dangling.h>
24+
#include <type_traits>
25+
26+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27+
#pragma GCC system_header
28+
#endif
29+
30+
_LIBCPP_BEGIN_NAMESPACE_STD
31+
32+
#if !defined(_LIBCPP_HAS_NO_RANGES)
33+
namespace ranges {
34+
35+
// uninitialized_default_construct
36+
37+
namespace __uninitialized_default_construct {
38+
39+
struct __fn final : private __function_like {
40+
41+
constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {}
42+
43+
template <__nothrow_forward_iterator _ForwardIterator,
44+
__nothrow_sentinel_for<_ForwardIterator> _Sentinel>
45+
requires default_initializable<iter_value_t<_ForwardIterator>>
46+
_ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const {
47+
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
48+
return _VSTD::__uninitialized_default_construct<_ValueType>(__first, __last);
49+
}
50+
51+
template <__nothrow_forward_range _ForwardRange>
52+
requires default_initializable<range_value_t<_ForwardRange>>
53+
borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const {
54+
return (*this)(ranges::begin(__range), ranges::end(__range));
55+
}
56+
57+
};
58+
59+
} // namespace __uninitialized_default_construct_ns
60+
61+
inline namespace __cpo {
62+
inline constexpr auto uninitialized_default_construct =
63+
__uninitialized_default_construct::__fn(__function_like::__tag());
64+
} // namespace __cpo
65+
66+
// uninitialized_default_construct_n
67+
68+
namespace __uninitialized_default_construct_n {
69+
70+
struct __fn final : private __function_like {
71+
72+
constexpr explicit __fn(__tag __x) noexcept :
73+
__function_like(__x) {}
74+
75+
template <__nothrow_forward_iterator _ForwardIterator>
76+
requires default_initializable<iter_value_t<_ForwardIterator>>
77+
_ForwardIterator operator()(_ForwardIterator __first,
78+
iter_difference_t<_ForwardIterator> __n) const {
79+
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
80+
return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n);
81+
}
82+
83+
};
84+
85+
} // namespace __uninitialized_default_construct_n_ns
86+
87+
inline namespace __cpo {
88+
inline constexpr auto uninitialized_default_construct_n =
89+
__uninitialized_default_construct_n::__fn(__function_like::__tag());
90+
} // namespace __cpo
91+
92+
} // namespace ranges
93+
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
94+
95+
_LIBCPP_END_NAMESPACE_STD
96+
97+
#endif // _LIBCPP___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H

libcxx/include/__memory/uninitialized_algorithms.h

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,43 +119,61 @@ uninitialized_fill_n(_ForwardIterator __f, _Size __n, const _Tp& __x)
119119

120120
#if _LIBCPP_STD_VER > 14
121121

122-
template <class _ForwardIterator>
123-
inline _LIBCPP_INLINE_VISIBILITY
124-
void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
125-
using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
122+
// uninitialized_default_construct
123+
124+
template <class _ValueType, class _ForwardIterator, class _Sentinel>
125+
inline _LIBCPP_HIDE_FROM_ABI
126+
_ForwardIterator __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) {
126127
auto __idx = __first;
127128
#ifndef _LIBCPP_NO_EXCEPTIONS
128129
try {
129130
#endif
130131
for (; __idx != __last; ++__idx)
131-
::new ((void*)_VSTD::addressof(*__idx)) _Vt;
132+
::new ((void*)_VSTD::addressof(*__idx)) _ValueType;
132133
#ifndef _LIBCPP_NO_EXCEPTIONS
133134
} catch (...) {
134135
_VSTD::destroy(__first, __idx);
135136
throw;
136137
}
137138
#endif
139+
140+
return __idx;
138141
}
139142

140-
template <class _ForwardIterator, class _Size>
143+
template <class _ForwardIterator>
141144
inline _LIBCPP_INLINE_VISIBILITY
142-
_ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
143-
using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
145+
void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
146+
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
147+
(void)_VSTD::__uninitialized_default_construct<_ValueType>(__first, __last);
148+
}
149+
150+
// uninitialized_default_construct_n
151+
152+
template <class _ValueType, class _ForwardIterator, class _Size>
153+
inline _LIBCPP_HIDE_FROM_ABI
154+
_ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
144155
auto __idx = __first;
145156
#ifndef _LIBCPP_NO_EXCEPTIONS
146157
try {
147158
#endif
148159
for (; __n > 0; ++__idx, (void) --__n)
149-
::new ((void*)_VSTD::addressof(*__idx)) _Vt;
150-
return __idx;
160+
::new ((void*)_VSTD::addressof(*__idx)) _ValueType;
151161
#ifndef _LIBCPP_NO_EXCEPTIONS
152162
} catch (...) {
153163
_VSTD::destroy(__first, __idx);
154164
throw;
155165
}
156166
#endif
167+
168+
return __idx;
157169
}
158170

171+
template <class _ForwardIterator, class _Size>
172+
inline _LIBCPP_INLINE_VISIBILITY
173+
_ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
174+
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
175+
return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n);
176+
}
159177

160178
template <class _ForwardIterator>
161179
inline _LIBCPP_INLINE_VISIBILITY

libcxx/include/memory

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,21 @@ template <class ForwardIterator, class Size>
219219
template <class ForwardIterator>
220220
void uninitialized_default_construct(ForwardIterator first, ForwardIterator last);
221221
222+
template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel>
223+
requires default_initializable<iter_value_t<ForwardIterator>>
224+
ForwardIterator ranges::uninitialized_default_construct(ForwardIterator first, Sentinel last); // since C++20
225+
226+
template <nothrow-forward-range ForwardRange>
227+
requires default_initializable<range_value_t<ForwardRange>>
228+
borrowed_iterator_t<ForwardRange> ranges::uninitialized_default_construct(ForwardRange&& r); // since C++20
229+
222230
template <class ForwardIterator, class Size>
223231
ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n);
224232
233+
template <nothrow-forward-iterator ForwardIterator>
234+
requires default_initializable<iter_value_t<ForwardIterator>>
235+
ForwardIterator ranges::uninitialized_default_construct_n(ForwardIterator first, iter_difference_t<ForwardIterator> n); // since C++20
236+
225237
template <class Y> struct auto_ptr_ref {}; // deprecated in C++11, removed in C++17
226238
227239
template<class X>
@@ -672,6 +684,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
672684
#include <__memory/concepts.h>
673685
#include <__memory/construct_at.h>
674686
#include <__memory/pointer_traits.h>
687+
#include <__memory/ranges_uninitialized_algorithms.h>
675688
#include <__memory/raw_storage_iterator.h>
676689
#include <__memory/shared_ptr.h>
677690
#include <__memory/temporary_buffer.h>

libcxx/include/module.modulemap

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -630,22 +630,26 @@ module std [system] {
630630
export *
631631

632632
module __memory {
633-
module addressof { private header "__memory/addressof.h" }
634-
module allocation_guard { private header "__memory/allocation_guard.h" }
635-
module allocator { private header "__memory/allocator.h" }
636-
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }
637-
module allocator_traits { private header "__memory/allocator_traits.h" }
638-
module auto_ptr { private header "__memory/auto_ptr.h" }
639-
module compressed_pair { private header "__memory/compressed_pair.h" }
640-
module concepts { private header "__memory/concepts.h" }
641-
module construct_at { private header "__memory/construct_at.h" }
642-
module pointer_traits { private header "__memory/pointer_traits.h" }
643-
module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" }
644-
module shared_ptr { private header "__memory/shared_ptr.h" }
645-
module temporary_buffer { private header "__memory/temporary_buffer.h" }
646-
module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" }
647-
module unique_ptr { private header "__memory/unique_ptr.h" }
648-
module uses_allocator { private header "__memory/uses_allocator.h" }
633+
module addressof { private header "__memory/addressof.h" }
634+
module allocation_guard { private header "__memory/allocation_guard.h" }
635+
module allocator { private header "__memory/allocator.h" }
636+
module allocator_arg_t { private header "__memory/allocator_arg_t.h" }
637+
module allocator_traits { private header "__memory/allocator_traits.h" }
638+
module auto_ptr { private header "__memory/auto_ptr.h" }
639+
module compressed_pair { private header "__memory/compressed_pair.h" }
640+
module concepts { private header "__memory/concepts.h" }
641+
module construct_at { private header "__memory/construct_at.h" }
642+
module pointer_traits { private header "__memory/pointer_traits.h" }
643+
module ranges_uninitialized_algorithms {
644+
private header "__memory/ranges_uninitialized_algorithms.h"
645+
export __function_like
646+
}
647+
module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" }
648+
module shared_ptr { private header "__memory/shared_ptr.h" }
649+
module temporary_buffer { private header "__memory/temporary_buffer.h" }
650+
module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" }
651+
module unique_ptr { private header "__memory/unique_ptr.h" }
652+
module uses_allocator { private header "__memory/uses_allocator.h" }
649653
}
650654
}
651655
module mutex {
@@ -755,7 +759,10 @@ module std [system] {
755759
module common_view { private header "__ranges/common_view.h" }
756760
module concepts { private header "__ranges/concepts.h" }
757761
module copyable_box { private header "__ranges/copyable_box.h" }
758-
module counted { private header "__ranges/counted.h" }
762+
module counted {
763+
private header "__ranges/counted.h"
764+
export span
765+
}
759766
module dangling { private header "__ranges/dangling.h" }
760767
module data { private header "__ranges/data.h" }
761768
module drop_view { private header "__ranges/drop_view.h" }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
// REQUIRES: modules-build
10+
11+
// WARNING: This test was generated by 'generate_private_header_tests.py'
12+
// and should not be edited manually.
13+
14+
// expected-error@*:* {{use of private header from outside its module: '__memory/ranges_uninitialized_algorithms.h'}}
15+
#include <__memory/ranges_uninitialized_algorithms.h>

0 commit comments

Comments
 (0)