Skip to content

Commit c6b192a

Browse files
authored
[libc++][test] Do not assume array::iterator is a pointer (#100603)
In the tests I added for `ranges::find_last{_if{_not}}`, I accidentally introduced an assumption that `same_as<array<T, 0>::iterator, T*>`; this is a faulty assumption on MSVC-STL. Fixes #100498.
1 parent 55357d8 commit c6b192a

File tree

4 files changed

+104
-54
lines changed

4 files changed

+104
-54
lines changed

libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <algorithm>
2626
#include <array>
2727
#include <cassert>
28+
#include <memory>
2829
#include <ranges>
2930
#include <vector>
3031

@@ -61,7 +62,8 @@ template <class It, class Sent = It>
6162
constexpr void test_iterators() {
6263
using ValueT = std::iter_value_t<It>;
6364
auto make_range = [](auto& a) {
64-
return std::ranges::subrange(It(std::ranges::begin(a)), Sent(It(std::ranges::end(a))));
65+
return std::ranges::subrange(
66+
It(std::to_address(std::ranges::begin(a))), Sent(It(std::to_address(std::ranges::end(a)))));
6567
};
6668
{ // simple test
6769
{
@@ -91,7 +93,7 @@ constexpr void test_iterators() {
9193
std::array<ValueT, 0> a = {};
9294

9395
auto ret = std::ranges::find_last(make_range(a), 1).begin();
94-
assert(ret == It(a.begin()));
96+
assert(ret == It(a.data()));
9597
}
9698
}
9799

libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ constexpr void test_iterator_classes() {
9292
{
9393
std::array<int, 0> a = {};
9494

95-
auto ret = std::ranges::find_last_if(it(a.data()), sent(it(a.data())), [](auto&&) { return true; }).begin();
96-
assert(ret == it(a.data()));
95+
auto ret = std::ranges::find_last_if(it(a.begin()), sent(it(a.end())), [](auto&&) { return true; }).begin();
96+
assert(ret == it(a.end()));
9797
}
9898
{
9999
std::array<int, 0> a = {};
100100

101101
auto ret = std::ranges::find_last_if(make_range<it, sent>(a), [](auto&&) { return true; }).begin();
102-
assert(ret == it(a.begin()));
102+
assert(ret == it(a.end()));
103103
}
104104
}
105105

@@ -183,8 +183,17 @@ struct NonConstComparable {
183183
friend constexpr bool operator==(NonConstComparable&, const NonConstComparable&) { return true; }
184184
};
185185

186+
// TODO: this should really use `std::const_iterator`
186187
template <class T>
187-
using add_const_to_ptr_t = std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>;
188+
struct add_const_to_ptr {
189+
using type = T;
190+
};
191+
template <class T>
192+
struct add_const_to_ptr<T*> {
193+
using type = const T*;
194+
};
195+
template <class T>
196+
using add_const_to_ptr_t = typename add_const_to_ptr<T>::type;
188197

189198
constexpr bool test() {
190199
test_iterator_classes<std::type_identity_t, std::type_identity_t>();

libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ constexpr void test_iterator_classes() {
9292
{
9393
std::array<int, 0> a = {};
9494

95-
auto ret = std::ranges::find_last_if_not(it(a.data()), sent(it(a.data())), [](auto&&) { return false; }).begin();
96-
assert(ret == it(a.data()));
95+
auto ret = std::ranges::find_last_if_not(it(a.begin()), sent(it(a.end())), [](auto&&) { return false; }).begin();
96+
assert(ret == it(a.end()));
9797
}
9898
{
9999
std::array<int, 0> a = {};
100100

101101
auto ret = std::ranges::find_last_if_not(make_range<it, sent>(a), [](auto&&) { return false; }).begin();
102-
assert(ret == it(a.begin()));
102+
assert(ret == it(a.end()));
103103
}
104104
}
105105

@@ -183,8 +183,17 @@ struct NonConstComparable {
183183
friend constexpr bool operator!=(NonConstComparable&, const NonConstComparable&) { return false; }
184184
};
185185

186+
// TODO: this should really use `std::const_iterator`
186187
template <class T>
187-
using add_const_to_ptr_t = std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>;
188+
struct add_const_to_ptr {
189+
using type = T;
190+
};
191+
template <class T>
192+
struct add_const_to_ptr<T*> {
193+
using type = const T*;
194+
};
195+
template <class T>
196+
using add_const_to_ptr_t = typename add_const_to_ptr<T>::type;
188197

189198
constexpr bool test() {
190199
test_iterator_classes<std::type_identity_t, std::type_identity_t>();

libcxx/test/support/test_iterators.h

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -339,62 +339,92 @@ cpp20_random_access_iterator(It) -> cpp20_random_access_iterator<It>;
339339

340340
static_assert(std::random_access_iterator<cpp20_random_access_iterator<int*>>);
341341

342-
template <class It>
343-
class contiguous_iterator
344-
{
345-
static_assert(std::is_pointer_v<It>, "Things probably break in this case");
342+
template <std::contiguous_iterator It>
343+
class contiguous_iterator {
344+
It it_;
346345

347-
It it_;
346+
template <std::contiguous_iterator U>
347+
friend class contiguous_iterator;
348348

349-
template <class U> friend class contiguous_iterator;
350349
public:
351-
typedef std::contiguous_iterator_tag iterator_category;
352-
typedef typename std::iterator_traits<It>::value_type value_type;
353-
typedef typename std::iterator_traits<It>::difference_type difference_type;
354-
typedef It pointer;
355-
typedef typename std::iterator_traits<It>::reference reference;
356-
typedef typename std::remove_pointer<It>::type element_type;
350+
using iterator_category = std::contiguous_iterator_tag;
351+
using value_type = typename std::iterator_traits<It>::value_type;
352+
using difference_type = typename std::iterator_traits<It>::difference_type;
353+
using pointer = typename std::iterator_traits<It>::pointer;
354+
using reference = typename std::iterator_traits<It>::reference;
355+
using element_type = value_type;
357356

358-
TEST_CONSTEXPR_CXX14 It base() const {return it_;}
357+
constexpr It base() const { return it_; }
359358

360-
TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
361-
TEST_CONSTEXPR_CXX14 explicit contiguous_iterator(It it) : it_(it) {}
359+
constexpr contiguous_iterator() : it_() {}
360+
constexpr explicit contiguous_iterator(It it) : it_(it) {}
362361

363-
template <class U>
364-
TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
362+
template <class U>
363+
constexpr contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
365364

366-
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
367-
constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
365+
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
366+
constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) {
367+
u.it_ = U();
368+
}
368369

369-
TEST_CONSTEXPR reference operator*() const {return *it_;}
370-
TEST_CONSTEXPR pointer operator->() const {return it_;}
371-
TEST_CONSTEXPR reference operator[](difference_type n) const {return it_[n];}
372-
373-
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
374-
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
375-
TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) {return contiguous_iterator(it_++);}
376-
TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) {return contiguous_iterator(it_--);}
377-
378-
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
379-
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
380-
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(contiguous_iterator x, difference_type n) {x += n; return x;}
381-
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) {x += n; return x;}
382-
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(contiguous_iterator x, difference_type n) {x -= n; return x;}
383-
friend TEST_CONSTEXPR difference_type operator-(contiguous_iterator x, contiguous_iterator y) {return x.it_ - y.it_;}
384-
385-
friend TEST_CONSTEXPR bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ == y.it_;}
386-
friend TEST_CONSTEXPR bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ != y.it_;}
387-
friend TEST_CONSTEXPR bool operator< (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ < y.it_;}
388-
friend TEST_CONSTEXPR bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ <= y.it_;}
389-
friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;}
390-
friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;}
370+
constexpr reference operator*() const { return *it_; }
371+
constexpr pointer operator->() const { return it_; }
372+
constexpr reference operator[](difference_type n) const { return it_[n]; }
373+
374+
constexpr contiguous_iterator& operator++() {
375+
++it_;
376+
return *this;
377+
}
378+
constexpr contiguous_iterator& operator--() {
379+
--it_;
380+
return *this;
381+
}
382+
constexpr contiguous_iterator operator++(int) { return contiguous_iterator(it_++); }
383+
constexpr contiguous_iterator operator--(int) { return contiguous_iterator(it_--); }
384+
385+
constexpr contiguous_iterator& operator+=(difference_type n) {
386+
it_ += n;
387+
return *this;
388+
}
389+
constexpr contiguous_iterator& operator-=(difference_type n) {
390+
it_ -= n;
391+
return *this;
392+
}
393+
friend constexpr contiguous_iterator operator+(contiguous_iterator x, difference_type n) {
394+
x += n;
395+
return x;
396+
}
397+
friend constexpr contiguous_iterator operator+(difference_type n, contiguous_iterator x) {
398+
x += n;
399+
return x;
400+
}
401+
friend constexpr contiguous_iterator operator-(contiguous_iterator x, difference_type n) {
402+
x -= n;
403+
return x;
404+
}
405+
friend constexpr difference_type operator-(contiguous_iterator x, contiguous_iterator y) { return x.it_ - y.it_; }
406+
407+
friend constexpr bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {
408+
return x.it_ == y.it_;
409+
}
410+
friend constexpr bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {
411+
return x.it_ != y.it_;
412+
}
413+
friend constexpr bool operator<(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ < y.it_; }
414+
friend constexpr bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {
415+
return x.it_ <= y.it_;
416+
}
417+
friend constexpr bool operator>(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ > y.it_; }
418+
friend constexpr bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {
419+
return x.it_ >= y.it_;
420+
}
391421

392422
// Note no operator<=>, use three_way_contiguous_iterator for testing operator<=>
393423

394-
friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; }
424+
friend constexpr It base(const contiguous_iterator& i) { return i.it_; }
395425

396-
template <class T>
397-
void operator,(T const &) = delete;
426+
template <class T>
427+
void operator,(T const&) = delete;
398428
};
399429
template <class It>
400430
contiguous_iterator(It) -> contiguous_iterator<It>;

0 commit comments

Comments
 (0)