diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -171,9 +171,30 @@ return __p; } +template +struct _HasToAddress : false_type {}; + +template +struct _HasToAddress<_Pointer, + decltype((void)pointer_traits<_Pointer>::to_address(declval())) +> : true_type {}; + +template +struct _HasArrow : false_type {}; + +template +struct _HasArrow<_Pointer, + decltype((void)declval().operator->()) +> : true_type {}; + +template +struct _IsFancyPointer { + static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value; +}; + // enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers template ::value && !is_array<_Pointer>::value && !is_function<_Pointer>::value + _And, _IsFancyPointer<_Pointer> >::value > > _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename decay::__call(declval()))>::type @@ -208,7 +229,7 @@ template inline _LIBCPP_INLINE_VISIBILITY constexpr -auto to_address(const _Pointer& __p) noexcept { +auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) { return _VSTD::__to_address(__p); } #endif diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp @@ -13,6 +13,7 @@ #include #include +#include #include "test_iterators.h" @@ -208,3 +209,47 @@ // Template param is used instead of element_type. static_assert(std::random_access_iterator>); static_assert(std::contiguous_iterator>); + +template +struct no_operator_arrow { + typedef std::contiguous_iterator_tag iterator_category; + typedef int value_type; + typedef int element_type; + typedef std::ptrdiff_t difference_type; + typedef int* pointer; + typedef int& reference; + typedef no_operator_arrow self; + + no_operator_arrow(); + + reference operator*() const; + pointer operator->() const requires (!DisableArrow); + auto operator<=>(const self&) const = default; + + self& operator++(); + self operator++(int); + + self& operator--(); + self operator--(int); + + self& operator+=(difference_type n); + self operator+(difference_type n) const; + // Note: it's a template function to prevent a GCC warning ("friend declaration declares a non-template function"). + template + friend no_operator_arrow operator+(difference_type n, no_operator_arrow x); + + self& operator-=(difference_type n); + self operator-(difference_type n) const; + difference_type operator-(const self& n) const; + + reference operator[](difference_type n) const; +}; + +template<> +struct std::pointer_traits> { + static constexpr int *to_address(const no_operator_arrow&); +}; + +static_assert(std::contiguous_iterator>); +static_assert(!std::contiguous_iterator>); +static_assert(std::contiguous_iterator>);