Skip to content

Commit dd48913

Browse files
authored
[libc++] Fix _CopySegment helper in ranges::copy(join_view, out) when called in a static assertion context (#69593)
Resolves Issue #69083 The `_CopySegment` helper for `ranges::copy(join_view, out)` is not `constexpr` causing rejection in `libc++` in a static assertion context as in the issue snippet.
1 parent e9a7876 commit dd48913

File tree

7 files changed

+468
-8
lines changed

7 files changed

+468
-8
lines changed

libcxx/include/__algorithm/copy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ struct __copy_loop {
5151

5252
_OutIter& __result_;
5353

54-
_LIBCPP_HIDE_FROM_ABI _CopySegment(_OutIter& __result) : __result_(__result) {}
54+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _CopySegment(_OutIter& __result)
55+
: __result_(__result) {}
5556

56-
_LIBCPP_HIDE_FROM_ABI void
57+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
5758
operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
5859
__result_ = std::__copy<_AlgPolicy>(__lfirst, __llast, std::move(__result_)).second;
5960
}

libcxx/include/__algorithm/move.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ struct __move_loop {
5252

5353
_OutIter& __result_;
5454

55-
_LIBCPP_HIDE_FROM_ABI _MoveSegment(_OutIter& __result) : __result_(__result) {}
55+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _MoveSegment(_OutIter& __result)
56+
: __result_(__result) {}
5657

57-
_LIBCPP_HIDE_FROM_ABI void
58+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
5859
operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) {
5960
__result_ = std::__move<_AlgPolicy>(__lfirst, __llast, std::move(__result_)).second;
6061
}

libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.segmented.pass.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,24 @@ constexpr void test_join_view() {
9292
}
9393
}
9494

95-
int main(int, char**) {
96-
test_containers<std::deque<int>, std::deque<int>>();
97-
test_containers<std::deque<int>, std::vector<int>>();
98-
test_containers<std::vector<int>, std::deque<int>>();
95+
constexpr bool test_constexpr() {
9996
test_containers<std::vector<int>, std::vector<int>>();
10097

10198
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
10299
test_join_view<Iter, Iter>();
103100
test_join_view<Iter, sentinel_wrapper<Iter>>();
104101
test_join_view<Iter, sized_sentinel<Iter>>();
105102
});
103+
return true;
104+
}
105+
106+
int main(int, char**) {
107+
test_containers<std::deque<int>, std::deque<int>>();
108+
test_containers<std::deque<int>, std::vector<int>>();
109+
test_containers<std::vector<int>, std::deque<int>>();
110+
111+
test_constexpr();
112+
static_assert(test_constexpr());
106113

107114
return 0;
108115
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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+
// TODO: make `join_view` non-experimental once D2770 is implemented.
11+
// UNSUPPORTED: !c++experimental
12+
13+
#include <algorithm>
14+
#include <array>
15+
#include <cassert>
16+
#include <concepts>
17+
#include <deque>
18+
#include <ranges>
19+
#include <vector>
20+
21+
#include "test_iterators.h"
22+
#include "type_algorithms.h"
23+
24+
template <class InContainer, class OutContainer>
25+
constexpr void test_containers() {
26+
using InIter = typename InContainer::iterator;
27+
using OutIter = typename OutContainer::iterator;
28+
29+
{
30+
InContainer in{1, 2, 3, 4};
31+
OutContainer out(4);
32+
33+
std::same_as<std::ranges::in_out_result<InIter, OutIter>> auto ret =
34+
std::ranges::copy_backward(in.begin(), in.end(), out.end());
35+
assert(std::ranges::equal(in, out));
36+
assert(ret.in == in.end());
37+
assert(ret.out == out.begin());
38+
}
39+
{
40+
InContainer in{1, 2, 3, 4};
41+
OutContainer out(4);
42+
std::same_as<std::ranges::in_out_result<InIter, OutIter>> auto ret = std::ranges::copy_backward(in, out.end());
43+
assert(std::ranges::equal(in, out));
44+
assert(ret.in == in.end());
45+
assert(ret.out == out.begin());
46+
}
47+
}
48+
49+
template <class Iter, class Sent>
50+
constexpr void test_join_view() {
51+
auto to_subranges = std::views::transform([](auto& vec) {
52+
return std::ranges::subrange(Iter(vec.data()), Sent(Iter(vec.data() + vec.size())));
53+
});
54+
55+
{ // segmented -> contiguous
56+
std::vector<std::vector<int>> vectors = {};
57+
auto range = vectors | to_subranges;
58+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
59+
std::array<int, 0> arr;
60+
61+
std::ranges::copy_backward(subrange_vector | std::views::join, arr.end());
62+
assert(std::ranges::equal(arr, std::array<int, 0>{}));
63+
}
64+
{ // segmented -> contiguous
65+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
66+
auto range = vectors | to_subranges;
67+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
68+
std::array<int, 10> arr;
69+
70+
std::ranges::copy_backward(subrange_vector | std::views::join, arr.end());
71+
assert(std::ranges::equal(arr, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
72+
}
73+
{ // contiguous -> segmented
74+
std::vector<std::vector<int>> vectors = {{0, 0, 0, 0}, {0, 0}, {0, 0, 0, 0}, {}};
75+
auto range = vectors | to_subranges;
76+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
77+
std::array arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
78+
79+
std::ranges::copy_backward(arr, (subrange_vector | std::views::join).end());
80+
assert(std::ranges::equal(subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
81+
}
82+
{ // segmented -> segmented
83+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
84+
auto range1 = vectors | to_subranges;
85+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range1.begin(), range1.end());
86+
std::vector<std::vector<int>> to_vectors = {{0, 0, 0, 0}, {0, 0, 0, 0}, {}, {0, 0}};
87+
auto range2 = to_vectors | to_subranges;
88+
std::vector<std::ranges::subrange<Iter, Sent>> to_subrange_vector(range2.begin(), range2.end());
89+
90+
std::ranges::copy_backward(subrange_vector | std::views::join, (to_subrange_vector | std::views::join).end());
91+
assert(std::ranges::equal(to_subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
92+
}
93+
}
94+
95+
constexpr bool test_constexpr() {
96+
test_containers<std::vector<int>, std::vector<int>>();
97+
98+
types::for_each(types::bidirectional_iterator_list<int*>{}, []<class Iter> { test_join_view<Iter, Iter>(); });
99+
return true;
100+
}
101+
102+
int main(int, char**) {
103+
test_containers<std::deque<int>, std::deque<int>>();
104+
test_containers<std::deque<int>, std::vector<int>>();
105+
test_containers<std::vector<int>, std::deque<int>>();
106+
107+
test_constexpr();
108+
static_assert(test_constexpr());
109+
110+
return 0;
111+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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+
// TODO: make `join_view` non-experimental once D2770 is implemented.
11+
// UNSUPPORTED: !c++experimental
12+
13+
#include <algorithm>
14+
#include <array>
15+
#include <cassert>
16+
#include <concepts>
17+
#include <deque>
18+
#include <ranges>
19+
#include <vector>
20+
21+
#include "test_iterators.h"
22+
#include "type_algorithms.h"
23+
24+
template <class InContainer, class OutContainer>
25+
constexpr void test_containers() {
26+
using InIter = typename InContainer::iterator;
27+
using OutIter = typename OutContainer::iterator;
28+
29+
{
30+
InContainer in{1, 2, 3, 4};
31+
OutContainer out(4);
32+
33+
std::same_as<std::ranges::in_out_result<InIter, OutIter>> auto ret =
34+
std::ranges::copy_n(in.begin(), in.size(), out.begin());
35+
assert(std::ranges::equal(in, out));
36+
assert(ret.in == in.end());
37+
assert(ret.out == out.end());
38+
}
39+
}
40+
41+
template <class Iter, class Sent>
42+
constexpr void test_join_view() {
43+
auto to_subranges = std::views::transform([](auto& vec) {
44+
return std::ranges::subrange(Iter(vec.data()), Sent(Iter(vec.data() + vec.size())));
45+
});
46+
47+
{ // segmented -> contiguous
48+
std::vector<std::vector<int>> vectors = {};
49+
auto range = vectors | to_subranges;
50+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
51+
std::array<int, 0> arr;
52+
53+
std::ranges::copy_n((subrange_vector | std::views::join).begin(),
54+
std::ranges::distance(subrange_vector | std::views::join),
55+
arr.begin());
56+
assert(std::ranges::equal(arr, std::array<int, 0>{}));
57+
}
58+
{ // segmented -> contiguous
59+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
60+
auto range = vectors | to_subranges;
61+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
62+
std::array<int, 10> arr;
63+
64+
std::ranges::copy_n((subrange_vector | std::views::join).begin(),
65+
std::ranges::distance(subrange_vector | std::views::join),
66+
arr.begin());
67+
assert(std::ranges::equal(arr, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
68+
}
69+
{ // contiguous -> segmented
70+
std::vector<std::vector<int>> vectors = {{0, 0, 0, 0}, {0, 0}, {0, 0, 0, 0}, {}};
71+
auto range = vectors | to_subranges;
72+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
73+
std::array arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
74+
75+
std::ranges::copy_n(arr.begin(), arr.size(), (subrange_vector | std::views::join).begin());
76+
assert(std::ranges::equal(subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
77+
}
78+
{ // segmented -> segmented
79+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
80+
auto range1 = vectors | to_subranges;
81+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range1.begin(), range1.end());
82+
std::vector<std::vector<int>> to_vectors = {{0, 0, 0, 0}, {0, 0, 0, 0}, {}, {0, 0}};
83+
auto range2 = to_vectors | to_subranges;
84+
std::vector<std::ranges::subrange<Iter, Sent>> to_subrange_vector(range2.begin(), range2.end());
85+
86+
std::ranges::copy_n((subrange_vector | std::views::join).begin(),
87+
std::ranges::distance(subrange_vector | std::views::join),
88+
(to_subrange_vector | std::views::join).begin());
89+
assert(std::ranges::equal(to_subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
90+
}
91+
}
92+
93+
constexpr bool test_constexpr() {
94+
test_containers<std::vector<int>, std::vector<int>>();
95+
96+
// TODO: this should be cpp20_input_iterator_list, not forward_iterator_list
97+
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
98+
test_join_view<Iter, Iter>();
99+
test_join_view<Iter, sentinel_wrapper<Iter>>();
100+
test_join_view<Iter, sized_sentinel<Iter>>();
101+
});
102+
return true;
103+
}
104+
105+
int main(int, char**) {
106+
test_containers<std::deque<int>, std::deque<int>>();
107+
test_containers<std::deque<int>, std::vector<int>>();
108+
test_containers<std::vector<int>, std::deque<int>>();
109+
110+
test_constexpr();
111+
static_assert(test_constexpr());
112+
113+
return 0;
114+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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+
// TODO: make `join_view` non-experimental once D2770 is implemented.
11+
// UNSUPPORTED: !c++experimental
12+
13+
#include <algorithm>
14+
#include <array>
15+
#include <cassert>
16+
#include <concepts>
17+
#include <deque>
18+
#include <ranges>
19+
#include <vector>
20+
21+
#include "test_iterators.h"
22+
#include "type_algorithms.h"
23+
24+
template <class InContainer, class OutContainer>
25+
constexpr void test_containers() {
26+
using InIter = typename InContainer::iterator;
27+
using OutIter = typename OutContainer::iterator;
28+
29+
{
30+
InContainer in{1, 2, 3, 4};
31+
OutContainer out(4);
32+
33+
std::same_as<std::ranges::in_out_result<InIter, OutIter>> auto ret =
34+
std::ranges::move(in.begin(), in.end(), out.begin());
35+
assert(std::ranges::equal(in, out));
36+
assert(ret.in == in.end());
37+
assert(ret.out == out.end());
38+
}
39+
{
40+
InContainer in{1, 2, 3, 4};
41+
OutContainer out(4);
42+
std::same_as<std::ranges::in_out_result<InIter, OutIter>> auto ret = std::ranges::move(in, out.begin());
43+
assert(std::ranges::equal(in, out));
44+
assert(ret.in == in.end());
45+
assert(ret.out == out.end());
46+
}
47+
}
48+
49+
template <class Iter, class Sent>
50+
constexpr void test_join_view() {
51+
auto to_subranges = std::views::transform([](auto& vec) {
52+
return std::ranges::subrange(Iter(vec.data()), Sent(Iter(vec.data() + vec.size())));
53+
});
54+
55+
{ // segmented -> contiguous
56+
std::vector<std::vector<int>> vectors = {};
57+
auto range = vectors | to_subranges;
58+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
59+
std::array<int, 0> arr;
60+
61+
std::ranges::move(subrange_vector | std::views::join, arr.begin());
62+
assert(std::ranges::equal(arr, std::array<int, 0>{}));
63+
}
64+
{ // segmented -> contiguous
65+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
66+
auto range = vectors | to_subranges;
67+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
68+
std::array<int, 10> arr;
69+
70+
std::ranges::move(subrange_vector | std::views::join, arr.begin());
71+
assert(std::ranges::equal(arr, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
72+
}
73+
{ // contiguous -> segmented
74+
std::vector<std::vector<int>> vectors = {{0, 0, 0, 0}, {0, 0}, {0, 0, 0, 0}, {}};
75+
auto range = vectors | to_subranges;
76+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range.begin(), range.end());
77+
std::array arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
78+
79+
std::ranges::move(arr, (subrange_vector | std::views::join).begin());
80+
assert(std::ranges::equal(subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
81+
}
82+
{ // segmented -> segmented
83+
std::vector<std::vector<int>> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}};
84+
auto range1 = vectors | to_subranges;
85+
std::vector<std::ranges::subrange<Iter, Sent>> subrange_vector(range1.begin(), range1.end());
86+
std::vector<std::vector<int>> to_vectors = {{0, 0, 0, 0}, {0, 0, 0, 0}, {}, {0, 0}};
87+
auto range2 = to_vectors | to_subranges;
88+
std::vector<std::ranges::subrange<Iter, Sent>> to_subrange_vector(range2.begin(), range2.end());
89+
90+
std::ranges::move(subrange_vector | std::views::join, (to_subrange_vector | std::views::join).begin());
91+
assert(std::ranges::equal(to_subrange_vector | std::views::join, std::array{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
92+
}
93+
}
94+
95+
constexpr bool test_constexpr() {
96+
test_containers<std::vector<int>, std::vector<int>>();
97+
98+
types::for_each(types::forward_iterator_list<int*>{}, []<class Iter> {
99+
test_join_view<Iter, Iter>();
100+
test_join_view<Iter, sentinel_wrapper<Iter>>();
101+
test_join_view<Iter, sized_sentinel<Iter>>();
102+
});
103+
return true;
104+
}
105+
106+
int main(int, char**) {
107+
test_containers<std::deque<int>, std::deque<int>>();
108+
test_containers<std::deque<int>, std::vector<int>>();
109+
test_containers<std::vector<int>, std::deque<int>>();
110+
111+
test_constexpr();
112+
static_assert(test_constexpr());
113+
114+
return 0;
115+
}

0 commit comments

Comments
 (0)