diff --git a/libcxx/include/__memory/pointer_traits.h b/libcxx/include/__memory/pointer_traits.h --- a/libcxx/include/__memory/pointer_traits.h +++ b/libcxx/include/__memory/pointer_traits.h @@ -164,11 +164,21 @@ // to_address -template struct __to_address_helper; +template +inline _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 <> struct __to_address_helper { +template +struct __to_address_helper { template - using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval())); + using __return_type = typename decay< + decltype(pointer_traits<_Pointer>::to_address(declval())) + >::type; template _LIBCPP_CONSTEXPR @@ -179,15 +189,6 @@ template using __choose_to_address = __to_address_helper<_IsValidExpansion<__to_address_helper<_Dummy>::template __return_type, _Pointer>::value>; -template -inline _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 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR typename __choose_to_address<_Pointer>::template __return_type<_Pointer> @@ -198,7 +199,9 @@ template <> struct __to_address_helper { template - using __return_type = typename pointer_traits<_Pointer>::element_type*; + using __return_type = typename decay< + decltype(_VSTD::__to_address(declval().operator->())) + >::type; template _LIBCPP_CONSTEXPR @@ -206,7 +209,6 @@ __do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); } }; - #if _LIBCPP_STD_VER > 17 template inline _LIBCPP_INLINE_VISIBILITY constexpr diff --git a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp --- a/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp +++ b/libcxx/test/std/utilities/memory/pointer.conversion/to_address.pass.cpp @@ -17,110 +17,84 @@ #include #include "test_macros.h" -class P1 -{ -public: - using element_type = int; +struct Irrelevant {}; - constexpr explicit P1(int* p) - : p_(p) { } - - constexpr int* operator->() const noexcept - { return p_; } - -private: - int* p_; +struct P1 { + using element_type = Irrelevant; + constexpr explicit P1(int *p) : p_(p) { } + constexpr int *operator->() const { return p_; } + int *p_; }; -class P2 -{ -public: - using element_type = int; - - constexpr explicit P2(int* p) - : p_(p) { } - - constexpr P1 operator->() const noexcept - { return p_; } - -private: +struct P2 { + using element_type = Irrelevant; + constexpr explicit P2(int *p) : p_(p) { } + constexpr P1 operator->() const { return p_; } P1 p_; }; -class P3 -{ -public: - constexpr explicit P3(int* p) - : p_(p) { } - - constexpr int* get() const noexcept - { return p_; } - -private: - int* p_; +struct P3 { + constexpr explicit P3(int *p) : p_(p) { } + int *p_; }; -namespace std -{ template<> -struct pointer_traits<::P3> -{ - static constexpr int* to_address(const ::P3& p) noexcept - { return p.get(); } +struct std::pointer_traits { + static constexpr int *to_address(const P3& p) { return p.p_; } }; -} - -class P4 -{ -public: - constexpr explicit P4(int* p) - : p_(p) { } - constexpr int* operator->() const noexcept - { return nullptr; } +struct P4 { + constexpr explicit P4(int *p) : p_(p) { } + int *operator->() const; // should never be called + int *p_; +}; - constexpr int* get() const noexcept - { return p_; } +template<> +struct std::pointer_traits { + static constexpr int *to_address(const P4& p) { return p.p_; } +}; -private: - int* p_; +struct P5 { + using element_type = Irrelevant; + int const* const& operator->() const; }; -namespace std -{ +struct P6 {}; + template<> -struct pointer_traits<::P4> -{ - constexpr static int* to_address(const ::P4& p) noexcept - { return p.get(); } +struct std::pointer_traits { + static int const* const& to_address(const P6&); }; -} int n = 0; static_assert(std::to_address(&n) == &n); constexpr bool test() { - int i = 0; - ASSERT_NOEXCEPT(std::to_address(&i)); - assert(std::to_address(&i) == &i); - P1 p1(&i); - ASSERT_NOEXCEPT(std::to_address(p1)); - assert(std::to_address(p1) == &i); - P2 p2(&i); - ASSERT_NOEXCEPT(std::to_address(p2)); - assert(std::to_address(p2) == &i); - P3 p3(&i); - ASSERT_NOEXCEPT(std::to_address(p3)); - assert(std::to_address(p3) == &i); - P4 p4(&i); - ASSERT_NOEXCEPT(std::to_address(p4)); - assert(std::to_address(p4) == &i); - - return true; + int i = 0; + ASSERT_NOEXCEPT(std::to_address(&i)); + assert(std::to_address(&i) == &i); + P1 p1(&i); + ASSERT_NOEXCEPT(std::to_address(p1)); + assert(std::to_address(p1) == &i); + P2 p2(&i); + ASSERT_NOEXCEPT(std::to_address(p2)); + assert(std::to_address(p2) == &i); + P3 p3(&i); + ASSERT_NOEXCEPT(std::to_address(p3)); + assert(std::to_address(p3) == &i); + P4 p4(&i); + ASSERT_NOEXCEPT(std::to_address(p4)); + assert(std::to_address(p4) == &i); + + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + ASSERT_SAME_TYPE(decltype(std::to_address(std::declval())), int const*); + + return true; } int main(int, char**) { - test(); - static_assert(test()); - return 0; + test(); + static_assert(test()); + return 0; }