From: Konstantin Varlamov Date: Thu, 4 Aug 2022 17:57:58 +0000 (-0700) Subject: [libc++] Fix a hard error in `contiguous_iterator`. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=52d4c5016c4f8eca6abe84f658fc5f358bdfd2d0;p=platform%2Fupstream%2Fllvm.git [libc++] Fix a hard error in `contiguous_iterator`. 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 --- diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h index c4cd56a..b9aa5fb 100644 --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -171,9 +171,30 @@ _Tp* __to_address(_Tp* __p) _NOEXCEPT { 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 @@ auto to_address(_Tp *__p) noexcept { 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 index b0c0e68..e442344 100644 --- 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 @@ struct template_and_no_element_type { // 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>);