[llvm-branch-commits] [libcxx] a447396 - [libc++] Fix a hard error in `contiguous_iterator<NoOperatorArrowIter>`.

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Aug 8 15:38:28 PDT 2022


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>>);


        


More information about the llvm-branch-commits mailing list