blob: 71d16e4e7e04b9d831a7aa9bf0f56591c9116322 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// This test is hitting Clang bugs with LSV in older versions of Clang.
// UNSUPPORTED: modules-build && (clang-15 || apple-clang-14)
// UNSUPPORTED: c++03, c++11, c++14, c++17
// constexpr iterator_t<V> operator->() const
// requires has-arrow<iterator_t<V>> && copyable<iterator_t<V>>
#include <ranges>
#include <array>
#include <cassert>
#include <concepts>
#include <cstddef>
#include <utility>
#include "test_iterators.h"
#include "test_macros.h"
#include "../types.h"
struct XYPoint {
int x;
int y;
};
template <class T>
concept has_arrow = requires (T t) {
{ t->x };
};
static_assert(has_arrow<XYPoint*>); // test the test
struct WithArrowOperator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = XYPoint;
constexpr explicit WithArrowOperator(XYPoint* p) : p_(p) { }
constexpr XYPoint& operator*() const { return *p_; }
constexpr XYPoint* operator->() const { return p_; } // has arrow
constexpr WithArrowOperator& operator++() { ++p_; return *this; }
constexpr WithArrowOperator operator++(int) { return WithArrowOperator(p_++); }
friend constexpr XYPoint* base(WithArrowOperator const& i) { return i.p_; }
XYPoint* p_;
};
static_assert(std::input_iterator<WithArrowOperator>);
struct WithNonCopyableIterator : std::ranges::view_base {
struct iterator {
using iterator_category = std::input_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = XYPoint;
iterator(iterator const&) = delete; // not copyable
iterator(iterator&&);
iterator& operator=(iterator&&);
XYPoint& operator*() const;
iterator operator->() const;
iterator& operator++();
iterator operator++(int);
// We need this to use XYPoint* as a sentinel type below. sentinel_wrapper
// can't be used because this iterator is not copyable.
friend bool operator==(iterator const&, XYPoint*);
};
iterator begin() const;
XYPoint* end() const;
};
static_assert(std::ranges::input_range<WithNonCopyableIterator>);
template <class Iterator, class Sentinel = sentinel_wrapper<Iterator>>
constexpr void test() {
std::array<XYPoint, 5> array{{{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}};
using View = minimal_view<Iterator, Sentinel>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterIterator = std::ranges::iterator_t<FilterView>;
auto make_filter_view = [](auto begin, auto end, auto pred) {
View view{Iterator(begin), Sentinel(Iterator(end))};
return FilterView(std::move(view), pred);
};
for (std::ptrdiff_t n = 0; n != 5; ++n) {
FilterView view = make_filter_view(array.begin(), array.end(), AlwaysTrue{});
FilterIterator const iter(view, Iterator(array.begin() + n));
std::same_as<Iterator> decltype(auto) result = iter.operator->();
assert(base(result) == array.begin() + n);
assert(iter->x == n);
assert(iter->y == n);
}
}
constexpr bool tests() {
test<WithArrowOperator>();
test<XYPoint*>();
test<XYPoint const*>();
test<contiguous_iterator<XYPoint*>>();
test<contiguous_iterator<XYPoint const*>>();
// Make sure filter_view::iterator doesn't have operator-> if the
// underlying iterator doesn't have one.
{
auto check_no_arrow = []<class It> {
using View = minimal_view<It, sentinel_wrapper<It>>;
using FilterView = std::ranges::filter_view<View, AlwaysTrue>;
using FilterIterator = std::ranges::iterator_t<FilterView>;
static_assert(!has_arrow<FilterIterator>);
};
check_no_arrow.operator()<cpp17_input_iterator<XYPoint*>>();
check_no_arrow.operator()<cpp20_input_iterator<XYPoint*>>();
check_no_arrow.operator()<forward_iterator<XYPoint*>>();
check_no_arrow.operator()<bidirectional_iterator<XYPoint*>>();
check_no_arrow.operator()<random_access_iterator<XYPoint*>>();
check_no_arrow.operator()<int*>();
}
// Make sure filter_view::iterator doesn't have operator-> if the
// underlying iterator is not copyable.
{
using FilterView = std::ranges::filter_view<WithNonCopyableIterator, AlwaysTrue>;
using FilterIterator = std::ranges::iterator_t<FilterView>;
static_assert(!has_arrow<FilterIterator>);
}
return true;
}
int main(int, char**) {
tests();
static_assert(tests());
return 0;
}