From e2713f3a45ed62bb2d543aded714f660ad115736 Mon Sep 17 00:00:00 2001 From: nicole mazzuca Date: Tue, 30 Jul 2024 11:28:56 +0200 Subject: [PATCH] [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::iterator, T*>`; this is a faulty assumption on MSVC-STL. Fixes #100498. --- .../alg.find.last/ranges.find_last.pass.cpp | 6 +- .../ranges.find_last_if.pass.cpp | 17 ++- .../ranges.find_last_if_not.pass.cpp | 17 ++- libcxx/test/support/test_iterators.h | 118 +++++++++++------- 4 files changed, 104 insertions(+), 54 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp index 2a2b12fb2c288dc..9da8c26db0f56f1 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last.pass.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,8 @@ template constexpr void test_iterators() { using ValueT = std::iter_value_t; 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 { @@ -91,7 +93,7 @@ constexpr void test_iterators() { std::array a = {}; auto ret = std::ranges::find_last(make_range(a), 1).begin(); - assert(ret == It(a.begin())); + assert(ret == It(a.data())); } } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp index a15f81bd4e481a4..107fcf900d3e447 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if.pass.cpp @@ -92,14 +92,14 @@ constexpr void test_iterator_classes() { { std::array 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 a = {}; auto ret = std::ranges::find_last_if(make_range(a), [](auto&&) { return true; }).begin(); - assert(ret == it(a.begin())); + assert(ret == it(a.end())); } } @@ -183,8 +183,17 @@ struct NonConstComparable { friend constexpr bool operator==(NonConstComparable&, const NonConstComparable&) { return true; } }; +// TODO: this should really use `std::const_iterator` template -using add_const_to_ptr_t = std::add_pointer_t>>; +struct add_const_to_ptr { + using type = T; +}; +template +struct add_const_to_ptr { + using type = const T*; +}; +template +using add_const_to_ptr_t = typename add_const_to_ptr::type; constexpr bool test() { test_iterator_classes(); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp index bb0e411acf0fa29..6602ac569c6794a 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.last/ranges.find_last_if_not.pass.cpp @@ -92,14 +92,14 @@ constexpr void test_iterator_classes() { { std::array 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 a = {}; auto ret = std::ranges::find_last_if_not(make_range(a), [](auto&&) { return false; }).begin(); - assert(ret == it(a.begin())); + assert(ret == it(a.end())); } } @@ -183,8 +183,17 @@ struct NonConstComparable { friend constexpr bool operator!=(NonConstComparable&, const NonConstComparable&) { return false; } }; +// TODO: this should really use `std::const_iterator` template -using add_const_to_ptr_t = std::add_pointer_t>>; +struct add_const_to_ptr { + using type = T; +}; +template +struct add_const_to_ptr { + using type = const T*; +}; +template +using add_const_to_ptr_t = typename add_const_to_ptr::type; constexpr bool test() { test_iterator_classes(); diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 95d1b7df0007cab..44bd4a597539de5 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -339,62 +339,92 @@ cpp20_random_access_iterator(It) -> cpp20_random_access_iterator; static_assert(std::random_access_iterator>); -template -class contiguous_iterator -{ - static_assert(std::is_pointer_v, "Things probably break in this case"); +template +class contiguous_iterator { + It it_; - It it_; + template + friend class contiguous_iterator; - template friend class contiguous_iterator; public: - typedef std::contiguous_iterator_tag iterator_category; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef It pointer; - typedef typename std::iterator_traits::reference reference; - typedef typename std::remove_pointer::type element_type; + using iterator_category = std::contiguous_iterator_tag; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::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 - TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator& u) : it_(u.it_) {} + template + constexpr contiguous_iterator(const contiguous_iterator& u) : it_(u.it_) {} - template ::value>::type> - constexpr contiguous_iterator(contiguous_iterator&& u) : it_(u.it_) { u.it_ = U(); } + template ::value>::type> + constexpr contiguous_iterator(contiguous_iterator&& 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 - void operator,(T const &) = delete; + template + void operator,(T const&) = delete; }; template contiguous_iterator(It) -> contiguous_iterator;