Skip to content

Commit

Permalink
[libc++][test] Do not assume array::iterator is a pointer (llvm#100603)
Browse files Browse the repository at this point in the history
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 llvm#100498.
  • Loading branch information
strega-nil authored and banach-space committed Aug 7, 2024
1 parent 18b8cd4 commit e2713f3
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <memory>
#include <ranges>
#include <vector>

Expand Down Expand Up @@ -61,7 +62,8 @@ template <class It, class Sent = It>
constexpr void test_iterators() {
using ValueT = std::iter_value_t<It>;
auto make_range = [](auto& a) {
return std::ranges::subrange(It(std::ranges::begin(a)), Sent(It(std::ranges::end(a))));
return std::ranges::subrange(
It(std::to_address(std::ranges::begin(a))), Sent(It(std::to_address(std::ranges::end(a)))));
};
{ // simple test
{
Expand Down Expand Up @@ -91,7 +93,7 @@ constexpr void test_iterators() {
std::array<ValueT, 0> a = {};

auto ret = std::ranges::find_last(make_range(a), 1).begin();
assert(ret == It(a.begin()));
assert(ret == It(a.data()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ constexpr void test_iterator_classes() {
{
std::array<int, 0> a = {};

auto ret = std::ranges::find_last_if(it(a.data()), sent(it(a.data())), [](auto&&) { return true; }).begin();
assert(ret == it(a.data()));
auto ret = std::ranges::find_last_if(it(a.begin()), sent(it(a.end())), [](auto&&) { return true; }).begin();
assert(ret == it(a.end()));
}
{
std::array<int, 0> a = {};

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

Expand Down Expand Up @@ -183,8 +183,17 @@ struct NonConstComparable {
friend constexpr bool operator==(NonConstComparable&, const NonConstComparable&) { return true; }
};

// TODO: this should really use `std::const_iterator`
template <class T>
using add_const_to_ptr_t = std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>;
struct add_const_to_ptr {
using type = T;
};
template <class T>
struct add_const_to_ptr<T*> {
using type = const T*;
};
template <class T>
using add_const_to_ptr_t = typename add_const_to_ptr<T>::type;

constexpr bool test() {
test_iterator_classes<std::type_identity_t, std::type_identity_t>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ constexpr void test_iterator_classes() {
{
std::array<int, 0> a = {};

auto ret = std::ranges::find_last_if_not(it(a.data()), sent(it(a.data())), [](auto&&) { return false; }).begin();
assert(ret == it(a.data()));
auto ret = std::ranges::find_last_if_not(it(a.begin()), sent(it(a.end())), [](auto&&) { return false; }).begin();
assert(ret == it(a.end()));
}
{
std::array<int, 0> a = {};

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

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

// TODO: this should really use `std::const_iterator`
template <class T>
using add_const_to_ptr_t = std::add_pointer_t<std::add_const_t<std::remove_pointer_t<T>>>;
struct add_const_to_ptr {
using type = T;
};
template <class T>
struct add_const_to_ptr<T*> {
using type = const T*;
};
template <class T>
using add_const_to_ptr_t = typename add_const_to_ptr<T>::type;

constexpr bool test() {
test_iterator_classes<std::type_identity_t, std::type_identity_t>();
Expand Down
118 changes: 74 additions & 44 deletions libcxx/test/support/test_iterators.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,62 +339,92 @@ cpp20_random_access_iterator(It) -> cpp20_random_access_iterator<It>;

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

template <class It>
class contiguous_iterator
{
static_assert(std::is_pointer_v<It>, "Things probably break in this case");
template <std::contiguous_iterator It>
class contiguous_iterator {
It it_;

It it_;
template <std::contiguous_iterator U>
friend class contiguous_iterator;

template <class U> friend class contiguous_iterator;
public:
typedef std::contiguous_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
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;
using iterator_category = std::contiguous_iterator_tag;
using value_type = typename std::iterator_traits<It>::value_type;
using difference_type = typename std::iterator_traits<It>::difference_type;
using pointer = typename std::iterator_traits<It>::pointer;
using reference = typename std::iterator_traits<It>::reference;
using element_type = value_type;

TEST_CONSTEXPR_CXX14 It base() const {return it_;}
constexpr It base() const { return it_; }

TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
TEST_CONSTEXPR_CXX14 explicit contiguous_iterator(It it) : it_(it) {}
constexpr contiguous_iterator() : it_() {}
constexpr explicit contiguous_iterator(It it) : it_(it) {}

template <class U>
TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}
template <class U>
constexpr contiguous_iterator(const contiguous_iterator<U>& u) : it_(u.it_) {}

template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) { u.it_ = U(); }
template <class U, class = typename std::enable_if<std::is_default_constructible<U>::value>::type>
constexpr contiguous_iterator(contiguous_iterator<U>&& u) : it_(u.it_) {
u.it_ = U();
}

TEST_CONSTEXPR reference operator*() const {return *it_;}
TEST_CONSTEXPR pointer operator->() const {return it_;}
TEST_CONSTEXPR reference operator[](difference_type n) const {return it_[n];}

TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int) {return contiguous_iterator(it_++);}
TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int) {return contiguous_iterator(it_--);}

TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {it_ -= n; return *this;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(contiguous_iterator x, difference_type n) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x) {x += n; return x;}
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(contiguous_iterator x, difference_type n) {x -= n; return x;}
friend TEST_CONSTEXPR difference_type operator-(contiguous_iterator x, contiguous_iterator y) {return x.it_ - y.it_;}

friend TEST_CONSTEXPR bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ == y.it_;}
friend TEST_CONSTEXPR bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ != y.it_;}
friend TEST_CONSTEXPR bool operator< (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ < y.it_;}
friend TEST_CONSTEXPR bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ <= y.it_;}
friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;}
friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;}
constexpr reference operator*() const { return *it_; }
constexpr pointer operator->() const { return it_; }
constexpr reference operator[](difference_type n) const { return it_[n]; }

constexpr contiguous_iterator& operator++() {
++it_;
return *this;
}
constexpr contiguous_iterator& operator--() {
--it_;
return *this;
}
constexpr contiguous_iterator operator++(int) { return contiguous_iterator(it_++); }
constexpr contiguous_iterator operator--(int) { return contiguous_iterator(it_--); }

constexpr contiguous_iterator& operator+=(difference_type n) {
it_ += n;
return *this;
}
constexpr contiguous_iterator& operator-=(difference_type n) {
it_ -= n;
return *this;
}
friend constexpr contiguous_iterator operator+(contiguous_iterator x, difference_type n) {
x += n;
return x;
}
friend constexpr contiguous_iterator operator+(difference_type n, contiguous_iterator x) {
x += n;
return x;
}
friend constexpr contiguous_iterator operator-(contiguous_iterator x, difference_type n) {
x -= n;
return x;
}
friend constexpr difference_type operator-(contiguous_iterator x, contiguous_iterator y) { return x.it_ - y.it_; }

friend constexpr bool operator==(const contiguous_iterator& x, const contiguous_iterator& y) {
return x.it_ == y.it_;
}
friend constexpr bool operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {
return x.it_ != y.it_;
}
friend constexpr bool operator<(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ < y.it_; }
friend constexpr bool operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {
return x.it_ <= y.it_;
}
friend constexpr bool operator>(const contiguous_iterator& x, const contiguous_iterator& y) { return x.it_ > y.it_; }
friend constexpr bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {
return x.it_ >= y.it_;
}

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

friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; }
friend constexpr It base(const contiguous_iterator& i) { return i.it_; }

template <class T>
void operator,(T const &) = delete;
template <class T>
void operator,(T const&) = delete;
};
template <class It>
contiguous_iterator(It) -> contiguous_iterator<It>;
Expand Down

0 comments on commit e2713f3

Please sign in to comment.