forked from OSchip/llvm-project
[libc++] Fix a hard error in `contiguous_iterator<NoOperatorArrowIter>`.
Evaluating `contiguous_iterator` on an iterator that satisfies all the constraints except the `to_address` constraint and doesn't have `operator->` defined results in a hard error. This is because instantiating `to_address` ends up instantiating templates dependent on the given type which might lead to a hard error even in a SFINAE context. Differential Revision: https://reviews.llvm.org/D130835
This commit is contained in:
parent
4038c859e5
commit
52d4c5016c
|
@ -171,9 +171,30 @@ _Tp* __to_address(_Tp* __p) _NOEXCEPT {
|
|||
return __p;
|
||||
}
|
||||
|
||||
template <class _Pointer, class = void>
|
||||
struct _HasToAddress : false_type {};
|
||||
|
||||
template <class _Pointer>
|
||||
struct _HasToAddress<_Pointer,
|
||||
decltype((void)pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))
|
||||
> : true_type {};
|
||||
|
||||
template <class _Pointer, class = void>
|
||||
struct _HasArrow : false_type {};
|
||||
|
||||
template <class _Pointer>
|
||||
struct _HasArrow<_Pointer,
|
||||
decltype((void)declval<const _Pointer&>().operator->())
|
||||
> : true_type {};
|
||||
|
||||
template <class _Pointer>
|
||||
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 <class _Pointer, class = __enable_if_t<
|
||||
!is_pointer<_Pointer>::value && !is_array<_Pointer>::value && !is_function<_Pointer>::value
|
||||
_And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value
|
||||
> >
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename decay<decltype(__to_address_helper<_Pointer>::__call(declval<const _Pointer&>()))>::type
|
||||
|
@ -208,7 +229,7 @@ auto to_address(_Tp *__p) noexcept {
|
|||
|
||||
template <class _Pointer>
|
||||
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
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <iterator>
|
||||
#include <compare>
|
||||
#include <memory>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
|
@ -208,3 +209,47 @@ struct template_and_no_element_type {
|
|||
// Template param is used instead of element_type.
|
||||
static_assert(std::random_access_iterator<template_and_no_element_type<int>>);
|
||||
static_assert(std::contiguous_iterator<template_and_no_element_type<int>>);
|
||||
|
||||
template <bool DisableArrow, bool DisableToAddress>
|
||||
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 <bool B1, bool B2>
|
||||
friend no_operator_arrow<B1, B2> operator+(difference_type n, no_operator_arrow<B1, B2> 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<no_operator_arrow</*DisableArrow=*/true, /*DisableToAddress=*/false>> {
|
||||
static constexpr int *to_address(const no_operator_arrow<true, false>&);
|
||||
};
|
||||
|
||||
static_assert(std::contiguous_iterator<no_operator_arrow</*DisableArrow=*/false, /*DisableToAddress=*/true>>);
|
||||
static_assert(!std::contiguous_iterator<no_operator_arrow</*DisableArrow=*/true, /*DisableToAddress=*/true>>);
|
||||
static_assert(std::contiguous_iterator<no_operator_arrow</*DisableArrow=*/true, /*DisableToAddress=*/false>>);
|
||||
|
|
Loading…
Reference in New Issue