Author: Konstantin Varlamov Date: 2022-08-08T13:29:17-07:00 New Revision: a447396dd7878fed889c3726834f032540ba6b30
URL: https://github.com/llvm/llvm-project/commit/a447396dd7878fed889c3726834f032540ba6b30 DIFF: https://github.com/llvm/llvm-project/commit/a447396dd7878fed889c3726834f032540ba6b30.diff LOG: [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 (cherry picked from commit 52d4c5016c4f8eca6abe84f658fc5f358bdfd2d0) Added: Modified: libcxx/include/__memory/pointer_traits.h libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.random.access/contiguous_iterator.compile.pass.cpp Removed: ################################################################################ diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h index c4cd56a21feab..b9aa5fbf243cb 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 <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 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 b0c0e68571256..e442344e252ba 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 <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::ptr diff _t diff erence_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+=( diff erence_type n); + self operator+( diff erence_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+( diff erence_type n, no_operator_arrow<B1, B2> x); + + self& operator-=( diff erence_type n); + self operator-( diff erence_type n) const; + diff erence_type operator-(const self& n) const; + + reference operator[]( diff erence_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>>); _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits