[libc++] Rewrite std::to_address to avoid relying on element_type

This is a rough reapplication of the change that fixed std::to_address
to avoid relying on element_type (da456167). It is somewhat different
because the fix to avoid breaking Clang (which caused it to be reverted
in 347f69c55) was a bit more involved.

Differential Revision: https://reviews.llvm.org/D101638

NOKEYCHECK=True
GitOrigin-RevId: fe0e86e6026f79e0b18f877196fbddd1d9e140d8
diff --git a/include/__memory/pointer_traits.h b/include/__memory/pointer_traits.h
index 439c658..6730066 100644
--- a/include/__memory/pointer_traits.h
+++ b/include/__memory/pointer_traits.h
@@ -164,64 +164,46 @@
 
 // to_address
 
-template <bool _UsePointerTraits> struct __to_address_helper;
-
-template <> struct __to_address_helper<true> {
-    template <class _Pointer>
-    using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval<const _Pointer&>()));
-
-    template <class _Pointer>
-    _LIBCPP_CONSTEXPR
-    static __return_type<_Pointer>
-    __do_it(const _Pointer &__p) _NOEXCEPT { return pointer_traits<_Pointer>::to_address(__p); }
-};
-
-template <class _Pointer, bool _Dummy = true>
-using __choose_to_address = __to_address_helper<_IsValidExpansion<__to_address_helper<_Dummy>::template __return_type, _Pointer>::value>;
+template <class _Pointer, class = void>
+struct __to_address_helper;
 
 template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-_Tp*
-__to_address(_Tp* __p) _NOEXCEPT
-{
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+_Tp* __to_address(_Tp* __p) _NOEXCEPT {
     static_assert(!is_function<_Tp>::value, "_Tp is a function type");
     return __p;
 }
 
-template <class _Pointer>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-typename __choose_to_address<_Pointer>::template __return_type<_Pointer>
-__to_address(const _Pointer& __p) _NOEXCEPT
-{
-    return __choose_to_address<_Pointer>::__do_it(__p);
+// enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
+template <class _Pointer, class = _EnableIf<!is_pointer<_Pointer>::value> >
+_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+typename decay<decltype(__to_address_helper<_Pointer>::__call(declval<const _Pointer&>()))>::type
+__to_address(const _Pointer& __p) _NOEXCEPT {
+    return __to_address_helper<_Pointer>::__call(__p);
 }
 
-template <> struct __to_address_helper<false> {
-    template <class _Pointer>
-    using __return_type = typename pointer_traits<_Pointer>::element_type*;
-
-    template <class _Pointer>
-    _LIBCPP_CONSTEXPR
-    static __return_type<_Pointer>
-    __do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); }
+template <class _Pointer, class>
+struct __to_address_helper {
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    static decltype(_VSTD::__to_address(declval<const _Pointer&>().operator->()))
+    __call(const _Pointer&__p) _NOEXCEPT {
+        return _VSTD::__to_address(__p.operator->());
+    }
 };
 
+template <class _Pointer>
+struct __to_address_helper<_Pointer, decltype((void)pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))> {
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    static decltype(pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))
+    __call(const _Pointer&__p) _NOEXCEPT {
+        return pointer_traits<_Pointer>::to_address(__p);
+    }
+};
 
 #if _LIBCPP_STD_VER > 17
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY constexpr
-_Tp*
-to_address(_Tp* __p) _NOEXCEPT
-{
-    static_assert(!is_function_v<_Tp>, "_Tp is a function type");
-    return __p;
-}
-
 template <class _Pointer>
 inline _LIBCPP_INLINE_VISIBILITY constexpr
-auto
-to_address(const _Pointer& __p) _NOEXCEPT
-{
+auto to_address(const _Pointer& __p) noexcept {
     return _VSTD::__to_address(__p);
 }
 #endif
diff --git a/include/iterator b/include/iterator
index 1d308a2..687c641 100644
--- a/include/iterator
+++ b/include/iterator
@@ -1356,7 +1356,7 @@
         _LIBCPP_ASSERT(__get_const_db()->__dereferenceable(this),
                        "Attempted to dereference a non-dereferenceable iterator");
 #endif
-        return (pointer)_VSTD::addressof(*__i);
+        return _VSTD::__to_address(__i);
     }
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG __wrap_iter& operator++() _NOEXCEPT
     {