-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[libc++][test] Fix assumptions that std::array
iterators are pointers
#74430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…rs are pointers. The error was pretty complicated, caused by the concepts machinery noticing that value_type and element_type were inconsistent: D:\GitHub\STL\llvm-project\libcxx\test\std\containers\views\views.span\span.cons\iterator_sentinel.pass.cpp(128,8): error: no matching constructor for initialization of 'std::span<int>' (std::span<int>{throw_operator_minus{a.begin()}, throw_operator_minus{a.end()}})); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ D:\GitHub\STL\llvm-project\libcxx\test\support\assert_macros.h(129,27): note: expanded from macro 'TEST_VALIDATE_EXCEPTION' static_cast<void>(EXPR); \ ^~~~ D:\GitHub\STL\out\x64\out\inc\span(328,51): note: candidate constructor template not viable: no known conversion from 'throw_operator_minus<_Array_iterator<int, 1>>' (aka 'throw_operator_minus<std::_Array_iterator<int, 1>>') to 'size_type' (aka 'unsigned long long') for 2nd argument constexpr explicit(_Extent != dynamic_extent) span(_It _First, size_type _Count) noexcept // strengthened ^ D:\GitHub\STL\out\x64\out\inc\span(339,51): note: candidate template ignored: constraints not satisfied [with _It = throw_operator_minus<_Array_iterator<int, 1>>, _Sentinel = throw_operator_minus<_Array_iterator<int, 1>>] constexpr explicit(_Extent != dynamic_extent) span(_It _First, _Sentinel _Last) ^ D:\GitHub\STL\out\x64\out\inc\span(338,15): note: because '_Span_compatible_iterator<throw_operator_minus<std::_Array_iterator<int, 1> >, element_type>' evaluated to false template <_Span_compatible_iterator<element_type> _It, _Span_compatible_sentinel<_It> _Sentinel> ^ D:\GitHub\STL\out\x64\out\inc\span(243,37): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'contiguous_iterator' concept _Span_compatible_iterator = contiguous_iterator<_It> ^ D:\GitHub\STL\out\x64\out\inc\xutility(815,31): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'random_access_iterator' concept contiguous_iterator = random_access_iterator<_It> ^ D:\GitHub\STL\out\x64\out\inc\xutility(803,34): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'bidirectional_iterator' concept random_access_iterator = bidirectional_iterator<_It> ^ D:\GitHub\STL\out\x64\out\inc\xutility(796,34): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'forward_iterator' concept bidirectional_iterator = forward_iterator<_It> && derived_from<_Iter_concept<_It>, bidirectional_iterator_tag> ^ D:\GitHub\STL\out\x64\out\inc\xutility(792,28): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'input_iterator' concept forward_iterator = input_iterator<_It> && derived_from<_Iter_concept<_It>, forward_iterator_tag> ^ D:\GitHub\STL\out\x64\out\inc\xutility(781,59): note: because 'throw_operator_minus<std::_Array_iterator<int, 1>>' does not satisfy 'indirectly_readable' concept input_iterator = input_or_output_iterator<_It> && indirectly_readable<_It> ^ D:\GitHub\STL\out\x64\out\inc\xutility(694,31): note: because 'remove_cvref_t<throw_operator_minus<_Array_iterator<int, 1>>>' (aka 'throw_operator_minus<std::_Array_iterator<int, 1>>') does not satisfy '_Indirectly_readable_impl' concept indirectly_readable = _Indirectly_readable_impl<remove_cvref_t<_It>>; ^ D:\GitHub\STL\out\x64\out\inc\__msvc_iter_core.hpp(163,1): note: because 'typename iter_value_t<_It>' would be invalid: no type named 'value_type' in 'std::indirectly_readable_traits<throw_operator_minus<std::_Array_iterator<int, 1>>>' using iter_value_t = conditional_t<_Is_from_primary<iterator_traits<remove_cvref_t<_Ty>>>, ^ D:\GitHub\STL\out\x64\out\inc\span(353,15): note: candidate constructor template not viable: requires single argument '_Arr', but 2 arguments were provided constexpr span(type_identity_t<element_type> (&_Arr)[_Size]) noexcept : _Mybase(_Arr, _Size) {} ^ D:\GitHub\STL\out\x64\out\inc\span(358,15): note: candidate constructor template not viable: requires single argument '_Arr', but 2 arguments were provided constexpr span(array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {} ^ D:\GitHub\STL\out\x64\out\inc\span(363,15): note: candidate constructor template not viable: requires single argument '_Arr', but 2 arguments were provided constexpr span(const array<_OtherTy, _Size>& _Arr) noexcept : _Mybase(_Arr.data(), _Size) {} ^ D:\GitHub\STL\out\x64\out\inc\span(366,51): note: candidate constructor template not viable: requires single argument '_Range', but 2 arguments were provided constexpr explicit(_Extent != dynamic_extent) span(_Rng&& _Range) ^ D:\GitHub\STL\out\x64\out\inc\span(380,5): note: candidate constructor template not viable: requires single argument '_Other', but 2 arguments were provided span(const span<_OtherTy, _OtherExtent>& _Other) noexcept ^ D:\GitHub\STL\out\x64\out\inc\span(297,7): note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided class span : private _Span_extent_type<_Ty, _Extent> { ^ D:\GitHub\STL\out\x64\out\inc\span(297,7): note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided D:\GitHub\STL\out\x64\out\inc\span(325,15): note: candidate constructor not viable: requires 0 arguments, but 2 were provided constexpr span() noexcept requires (_Extent == 0 || _Extent == dynamic_extent) = default; ^
wrap_input() is called with Iter types that are constructible from raw pointers. It's also sometimes called with an `array` as the `input`, so the first overload was implicitly assuming that array iterators are pointers. We can fix this assumption by providing a dedicated overload for `array`, just like the one for `vector` immediately below. Finally, from_range_helpers.h should explicitly include both `<array>` and `<vector>`, even though they were apparently being dragged in already.
This is called immediately below with arrays and pointer types.
@llvm/pr-subscribers-libcxx Author: Stephan T. Lavavej (StephanTLavavej) ChangesFound while running libc++'s tests with MSVC's STL, where Most of these changes are reasonably self-explanatory (the In In <details><summary>Click to expand error:</summary>
</details> Fortunately, the fix is extremely simple. To produce Patch is 31.17 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/74430.diff 13 Files Affected:
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
index 751d6b74b0128..833d5b0f6b2bf 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace.pass.cpp
@@ -29,35 +29,35 @@ struct Test {
void operator()(ExecutionPolicy&& policy) {
{ // simple test
std::array a = {1, 2, 3, 4, 5, 6, 7, 8};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 6);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 6);
assert((a == std::array{1, 2, 6, 4, 5, 6, 7, 8}));
}
{ // empty range works
std::array<int, 0> a = {};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 6);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 6);
}
{ // non-empty range without a match works
std::array a = {1, 2};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 6);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 6);
}
{ // single element range works
std::array a = {3};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 6);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 6);
assert((a == std::array{6}));
}
{ // two element range works
std::array a = {3, 4};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 6);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 6);
assert((a == std::array{6, 4}));
}
{ // multiple matching elements work
std::array a = {1, 2, 3, 4, 3, 3, 5, 6, 3};
- std::replace(policy, Iter(std::begin(a)), Iter(std::end(a)), 3, 9);
+ std::replace(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), 3, 9);
assert((a == std::array{1, 2, 9, 4, 9, 9, 5, 6, 9}));
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
index f24bedabebccd..18d4446f5d2a9 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy.pass.cpp
@@ -32,40 +32,40 @@ struct Test {
{ // simple test
std::array a = {1, 2, 3, 4, 5, 6, 7, 8};
std::array<int, a.size()> out;
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), 3, 6);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), 3, 6);
assert((out == std::array{1, 2, 6, 4, 5, 6, 7, 8}));
}
{ // empty range works
std::array<int, 0> a = {};
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(a)), 3, 6);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(a)), 3, 6);
}
{ // non-empty range without a match works
std::array a = {1, 2};
std::array<int, a.size()> out;
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(out.data()), 3, 6);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(out.data()), 3, 6);
assert((out == std::array{1, 2}));
}
{ // single element range works
std::array a = {3};
std::array<int, a.size()> out;
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), 3, 6);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), 3, 6);
assert((out == std::array{6}));
}
{ // two element range works
std::array a = {3, 4};
std::array<int, a.size()> out;
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), 3, 6);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), 3, 6);
assert((out == std::array{6, 4}));
}
{ // multiple matching elements work
std::array a = {1, 2, 3, 4, 3, 3, 5, 6, 3};
std::array<int, a.size()> out;
- std::replace_copy(policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), 3, 9);
+ std::replace_copy(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), 3, 9);
assert((out == std::array{1, 2, 9, 4, 9, 9, 5, 6, 9}));
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
index f7c746f382d11..89ea1652eb896 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_copy_if.pass.cpp
@@ -34,21 +34,21 @@ struct Test {
std::array a = {1, 2, 3, 4, 5, 6, 7, 8};
std::array<int, a.size()> out;
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), [](int i) { return i == 3; }, 6);
assert((out == std::array{1, 2, 6, 4, 5, 6, 7, 8}));
}
{ // empty range works
std::array<int, 0> a = {};
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(a)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(a)), [](int i) { return i == 3; }, 6);
}
{ // non-empty range without a match works
std::array a = {1, 2};
std::array<int, a.size()> out;
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(out.data()), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(out.data()), [](int i) { return i == 3; }, 6);
assert((out == std::array{1, 2}));
}
@@ -56,7 +56,7 @@ struct Test {
std::array a = {3};
std::array<int, a.size()> out;
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), [](int i) { return i == 3; }, 6);
assert((out == std::array{6}));
}
@@ -64,7 +64,7 @@ struct Test {
std::array a = {3, 4};
std::array<int, a.size()> out;
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), [](int i) { return i == 3; }, 6);
assert((out == std::array{6, 4}));
}
@@ -72,7 +72,7 @@ struct Test {
std::array a = {1, 2, 3, 4, 3, 3, 5, 6, 3};
std::array<int, a.size()> out;
std::replace_copy_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), Iter(std::begin(out)), [](int i) { return i == 3; }, 9);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), Iter(std::data(out)), [](int i) { return i == 3; }, 9);
assert((out == std::array{1, 2, 9, 4, 9, 9, 5, 6, 9}));
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
index 3ffc1c021bb9c..99ea5e230835f 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/pstl.replace_if.pass.cpp
@@ -30,38 +30,38 @@ struct Test {
{ // simple test
std::array a = {1, 2, 3, 4, 5, 6, 7, 8};
std::replace_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 3 || i == 7; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int i) { return i == 3 || i == 7; }, 6);
assert((a == std::array{1, 2, 6, 4, 5, 6, 6, 8}));
}
{ // empty range works
std::array<int, 0> a = {};
std::replace_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), [](int) { return false; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int) { return false; }, 6);
}
{ // non-empty range without a match works
std::array a = {1, 2};
- std::replace_if(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int) { return false; }, 6);
+ std::replace_if(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int) { return false; }, 6);
}
{ // single element range works
std::array a = {3};
std::replace_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int i) { return i == 3; }, 6);
assert((a == std::array{6}));
}
{ // two element range works
std::array a = {3, 4};
std::replace_if(
- policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 3; }, 6);
+ policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int i) { return i == 3; }, 6);
assert((a == std::array{6, 4}));
}
{ // multiple matching elements work
std::array a = {1, 2, 3, 4, 3, 3, 5, 6, 3};
- std::replace_if(policy, Iter(std::begin(a)), Iter(std::end(a)), [](int i) { return i == 3; }, 9);
+ std::replace_if(policy, Iter(std::data(a)), Iter(std::data(a) + std::size(a)), [](int i) { return i == 3; }, 9);
assert((a == std::array{1, 2, 9, 4, 9, 9, 5, 6, 9}));
}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.pass.cpp
index 1feadfb377a68..c685bff8f4e9b 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.merge/pstl.merge.pass.cpp
@@ -54,14 +54,14 @@ struct Test {
std::array<int, 0> b;
std::array<int, std::size(a) + std::size(b)> out;
std::merge(
- policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), std::begin(out));
+ policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::data(b)), Iter2(std::data(b) + std::size(b)), std::begin(out));
}
{ // check that it works with the first range being empty
std::array<int, 0> a;
int b[] = {2, 4, 6, 8, 10};
std::array<int, std::size(a) + std::size(b)> out;
std::merge(
- policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), std::begin(out));
+ policy, Iter1(std::data(a)), Iter1(std::data(a) + std::size(a)), Iter2(std::begin(b)), Iter2(std::end(b)), std::begin(out));
assert((out == std::array{2, 4, 6, 8, 10}));
}
@@ -70,7 +70,7 @@ struct Test {
std::array<int, 0> b;
std::array<int, std::size(a) + std::size(b)> out;
std::merge(
- policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::begin(b)), Iter2(std::end(b)), std::begin(out));
+ policy, Iter1(std::begin(a)), Iter1(std::end(a)), Iter2(std::data(b)), Iter2(std::data(b) + std::size(b)), std::begin(out));
assert((out == std::array{2, 4, 6, 8, 10}));
}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
index 0bd1d74529530..17db46edfb218 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way.pass.cpp
@@ -28,7 +28,7 @@
template <typename Iter1, typename Iter2, typename C1, typename C2, typename Order>
constexpr void test_lexicographical_compare(C1 a, C2 b, Order expected) {
std::same_as<Order> decltype(auto) result =
- std::lexicographical_compare_three_way(Iter1{a.begin()}, Iter1{a.end()}, Iter2{b.begin()}, Iter2{b.end()});
+ std::lexicographical_compare_three_way(Iter1{a.data()}, Iter1{a.data() + a.size()}, Iter2{b.data()}, Iter2{b.data() + b.size()});
assert(expected == result);
}
diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp
index d3c2814d642a7..1f8b18737ada8 100644
--- a/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.sorting/alg.three.way/lexicographical_compare_three_way_comp.pass.cpp
@@ -57,7 +57,7 @@ static_assert(has_lexicographical_compare<decltype(compare_int_result)>);
template <typename Iter1, typename Iter2, typename C1, typename C2, typename Order, typename Comparator>
constexpr void test_lexicographical_compare(C1 a, C2 b, Comparator comp, Order expected) {
std::same_as<Order> decltype(auto) result =
- std::lexicographical_compare_three_way(Iter1{a.begin()}, Iter1{a.end()}, Iter2{b.begin()}, Iter2{b.end()}, comp);
+ std::lexicographical_compare_three_way(Iter1{a.data()}, Iter1{a.data() + a.size()}, Iter2{b.data()}, Iter2{b.data() + b.size()}, comp);
assert(expected == result);
}
diff --git a/libcxx/test/std/containers/from_range_helpers.h b/libcxx/test/std/containers/from_range_helpers.h
index 7fff99da1e15e..e17ea247618bc 100644
--- a/libcxx/test/std/containers/from_range_helpers.h
+++ b/libcxx/test/std/containers/from_range_helpers.h
@@ -9,9 +9,11 @@
#ifndef SUPPORT_FROM_RANGE_HELPERS_H
#define SUPPORT_FROM_RANGE_HELPERS_H
+#include <array>
#include <cstddef>
#include <iterator>
#include <type_traits>
+#include <vector>
#include "min_allocator.h"
#include "test_allocator.h"
@@ -34,6 +36,13 @@ constexpr auto wrap_input(Range&& input) {
return std::ranges::subrange(std::move(b), std::move(e));
}
+template <class Iter, class Sent, class T, std::size_t N>
+constexpr auto wrap_input(std::array<T, N>& input) {
+ auto b = Iter(input.data());
+ auto e = Sent(Iter(input.data() + input.size()));
+ return std::ranges::subrange(std::move(b), std::move(e));
+}
+
template <class Iter, class Sent, class T>
constexpr auto wrap_input(std::vector<T>& input) {
auto b = Iter(input.data());
diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
index 4e1db3df5b83b..73b13ccc34cf8 100644
--- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
@@ -71,7 +71,7 @@ class throw_operator_minus {
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
- typedef typename std::remove_pointer<It>::type element_type;
+ typedef std::remove_reference_t<reference> element_type;
throw_operator_minus() : it_() {}
explicit throw_operator_minus(It it) : it_(it) {}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/compare.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/compare.pass.cpp
index 38b6346e0061f..a3a51c79ccd12 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/compare.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/compare.pass.cpp
@@ -31,15 +31,15 @@ constexpr void test() {
using ChunkByView = std::ranges::chunk_by_view<Underlying, std::ranges::less_equal>;
using ChunkByIterator = std::ranges::iterator_t<ChunkByView>;
- auto make_chunk_by_view = [](auto begin, auto end) {
- View view{Iterator(begin), Sentinel(Iterator(end))};
+ auto make_chunk_by_view = [](auto& arr) {
+ View view{Iterator(arr.data()), Sentinel(Iterator(arr.data() + arr.size()))};
return ChunkByView(std::move(view), std::ranges::less_equal{});
};
// Test operator==
{
std::array array{0, 1, 2};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator i = view.begin();
ChunkByIterator j = view.begin();
@@ -52,7 +52,7 @@ constexpr void test() {
// Test synthesized operator!=
{
std::array array{0, 1, 2};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator i = view.begin();
ChunkByIterator j = view.begin();
@@ -65,7 +65,7 @@ constexpr void test() {
// Test operator== with std::default_sentinel_t
{
std::array array{0, 1, 2};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator i = view.begin();
std::same_as<bool> decltype(auto) result = (i == std::default_sentinel);
@@ -77,7 +77,7 @@ constexpr void test() {
// Test synthesized operator!= with std::default_sentinel_t
{
std::array array{0, 1, 2};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator i = view.begin();
std::same_as<bool> decltype(auto) result = (i != std::default_sentinel);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/decrement.pass.cpp
index 167f3f753bfae..a331c794c8815 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/decrement.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.chunk.by/range.chunk.by.iter/decrement.pass.cpp
@@ -51,107 +51,107 @@ constexpr void test() {
static_assert(HasPostDecrement<ChunkByIterator>);
static_assert(HasPreDecrement<ChunkByIterator>);
- auto make_chunk_by_view = [](auto begin, auto end) {
- View view{Iterator{begin}, Sentinel{Iterator{end}}};
+ auto make_chunk_by_view = [](auto& arr) {
+ View view{Iterator{arr.data()}, Sentinel{Iterator{arr.data() + arr.size()}}};
return ChunkByView{std::move(view), std::ranges::less_equal{}};
};
// Test with a single chunk
{
std::array array{0, 1, 2, 3, 4};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator it = std::ranges::next(view.begin(), view.end());
std::same_as<ChunkByIterator&> decltype(auto) result = --it;
assert(&result == &it);
- assert(base((*result).begin()) == array.begin());
+ assert(base((*result).begin()) == array.data());
}
// Test with two chunks
{
std::array array{0, 1, 2, 0, 1, 2};
- ChunkByView view = make_chunk_by_view(array.begin(), array.end());
+ ChunkByView view = make_chunk_by_view(array);
ChunkByIterator it = std::ranges::next(view.begin(), view.end());
std::same_as<ChunkByIterator&> decltype(auto) result = --it;
assert(&result == &it);
- assert(base((*result).begin()) == array.begin() + 3);
+ assert(base((*result).begin()) == array.data() + 3);
--it;
- assert(base((*result).begin()) == array.begin());
+ assert(base((*result).begin()) == array.data());
}
// Test going forward and then backward on the same iterator
{
std::array array{7, 8, 9, 4, 5, 6, 1, 2, 3, 0};
- ChunkByView view ...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Found while running libc++'s tests with MSVC's STL, where
std::array
iterators are never pointers.Most of these changes are reasonably self-explanatory (the
std::array
s are right there, and the sometimes-slightly-wrapped raw pointer types are a short distance away). A couple of changes are less obvious:In
libcxx/test/std/containers/from_range_helpers.h
,wrap_input()
is called withIter
types that are constructible from raw pointers. It's also sometimes called with anarray
as theinput
, so the first overload was implicitly assuming thatarray
iterators are pointers. We can fix this assumption by providing a dedicated overload forarray
, just like the one forvector
immediately below. Finally,from_range_helpers.h
should explicitly include both<array>
and<vector>
, even though they were apparently being dragged in already.In
libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp
, fixthrow_operator_minus
. The error was pretty complicated, caused by the concepts machinery noticing thatvalue_type
andelement_type
were inconsistent. In the template instantiation context, you can see the critical detail thatthrow_operator_minus<std::_Array_iterator>
is being formed.Click to expand error:
Fortunately, the fix is extremely simple. To produce
element_type
(which retains any cv-qualification, unlikevalue_type
), we shouldn't attempt toremove_pointer
with the iterator typeIt
. Instead, we've already obtained thereference
type, so we canremove_reference_t
. (This is modern code, where we have access to the alias templates, so I saw no reason to use the older verbose form.)